Home | History | Annotate | Download | only in settingslib
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.settingslib;
     18 
     19 import android.app.Activity;
     20 import android.content.ActivityNotFoundException;
     21 import android.content.ComponentName;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.pm.PackageInfo;
     25 import android.content.pm.PackageManager.NameNotFoundException;
     26 import android.content.res.Resources;
     27 import android.content.res.Resources.Theme;
     28 import android.content.res.TypedArray;
     29 import android.net.Uri;
     30 import android.provider.Settings.Global;
     31 import android.text.TextUtils;
     32 import android.util.Log;
     33 import android.util.TypedValue;
     34 import android.view.Menu;
     35 import android.view.MenuItem;
     36 import android.view.MenuItem.OnMenuItemClickListener;
     37 
     38 import java.net.URISyntaxException;
     39 import java.util.Locale;
     40 
     41 /**
     42  * Functions to easily prepare contextual help menu option items with an intent that opens up the
     43  * browser to a particular URL, while taking into account the preferred language and app version.
     44  */
     45 public class HelpUtils {
     46     private final static String TAG = HelpUtils.class.getSimpleName();
     47 
     48     private static final int MENU_HELP = Menu.FIRST + 100;
     49 
     50     /**
     51      * Help URL query parameter key for the preferred language.
     52      */
     53     private final static String PARAM_LANGUAGE_CODE = "hl";
     54 
     55     /**
     56      * Help URL query parameter key for the app version.
     57      */
     58     private final static String PARAM_VERSION = "version";
     59 
     60     // Constants for help intents.
     61     private static final String EXTRA_CONTEXT = "EXTRA_CONTEXT";
     62     private static final String EXTRA_THEME = "EXTRA_THEME";
     63     private static final String EXTRA_PRIMARY_COLOR = "EXTRA_PRIMARY_COLOR";
     64     private static final String EXTRA_BACKUP_URI = "EXTRA_BACKUP_URI";
     65 
     66     /**
     67      * Cached version code to prevent repeated calls to the package manager.
     68      */
     69     private static String sCachedVersionCode = null;
     70 
     71     /** Static helper that is not instantiable*/
     72     private HelpUtils() { }
     73 
     74     public static boolean prepareHelpMenuItem(Activity activity, Menu menu, String helpUri,
     75             String backupContext) {
     76         MenuItem helpItem = menu.add(0, MENU_HELP, 0, R.string.help_feedback_label);
     77         return prepareHelpMenuItem(activity, helpItem, helpUri, backupContext);
     78     }
     79 
     80     public static boolean prepareHelpMenuItem(Activity activity, Menu menu, int helpUriResource,
     81             String backupContext) {
     82         MenuItem helpItem = menu.add(0, MENU_HELP, 0, R.string.help_feedback_label);
     83         return prepareHelpMenuItem(activity, helpItem, activity.getString(helpUriResource),
     84                 backupContext);
     85     }
     86 
     87     /**
     88      * Prepares the help menu item by doing the following.
     89      * - If the helpUrlString is empty or null, the help menu item is made invisible.
     90      * - Otherwise, this makes the help menu item visible and sets the intent for the help menu
     91      *   item to view the URL.
     92      *
     93      * @return returns whether the help menu item has been made visible.
     94      */
     95     public static boolean prepareHelpMenuItem(final Activity activity, MenuItem helpMenuItem,
     96             String helpUriString, String backupContext) {
     97         if (Global.getInt(activity.getContentResolver(), Global.DEVICE_PROVISIONED, 0) == 0) {
     98             return false;
     99         }
    100         if (TextUtils.isEmpty(helpUriString)) {
    101             // The help url string is empty or null, so set the help menu item to be invisible.
    102             helpMenuItem.setVisible(false);
    103 
    104             // return that the help menu item is not visible (i.e. false)
    105             return false;
    106         } else {
    107             final Intent intent = getHelpIntent(activity, helpUriString, backupContext);
    108 
    109             // Set the intent to the help menu item, show the help menu item in the overflow
    110             // menu, and make it visible.
    111             if (intent != null) {
    112                 helpMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
    113                     @Override
    114                     public boolean onMenuItemClick(MenuItem item) {
    115                         try {
    116                             activity.startActivityForResult(intent, 0);
    117                         } catch (ActivityNotFoundException exc) {
    118                             Log.e(TAG, "No activity found for intent: " + intent);
    119                         }
    120                         return true;
    121                     }
    122                 });
    123                 helpMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
    124                 helpMenuItem.setVisible(true);
    125             } else {
    126                 helpMenuItem.setVisible(false);
    127                 return false;
    128             }
    129 
    130             // return that the help menu item is visible (i.e., true)
    131             return true;
    132         }
    133     }
    134 
    135     public static Intent getHelpIntent(Context context, String helpUriString,
    136             String backupContext) {
    137         if (Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0) == 0) {
    138             return null;
    139         }
    140         // Try to handle as Intent Uri, otherwise just treat as Uri.
    141         try {
    142             Intent intent = Intent.parseUri(helpUriString,
    143                     Intent.URI_ANDROID_APP_SCHEME | Intent.URI_INTENT_SCHEME);
    144             addIntentParameters(context, intent, backupContext, true /* sendPackageName */);
    145             ComponentName component = intent.resolveActivity(context.getPackageManager());
    146             if (component != null) {
    147                 return intent;
    148             } else if (intent.hasExtra(EXTRA_BACKUP_URI)) {
    149                 // This extra contains a backup URI for when the intent isn't available.
    150                 return getHelpIntent(context, intent.getStringExtra(EXTRA_BACKUP_URI),
    151                         backupContext);
    152             } else {
    153                 return null;
    154             }
    155         } catch (URISyntaxException e) {
    156         }
    157         // The help url string exists, so first add in some extra query parameters.
    158         final Uri fullUri = uriWithAddedParameters(context, Uri.parse(helpUriString));
    159 
    160         // Then, create an intent that will be fired when the user
    161         // selects this help menu item.
    162         Intent intent = new Intent(Intent.ACTION_VIEW, fullUri);
    163         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
    164                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    165         return intent;
    166     }
    167 
    168     public static void addIntentParameters(Context context, Intent intent, String backupContext,
    169             boolean sendPackageName) {
    170         if (!intent.hasExtra(EXTRA_CONTEXT)) {
    171             // Insert some context if none exists.
    172             intent.putExtra(EXTRA_CONTEXT, backupContext);
    173         }
    174 
    175         Resources resources = context.getResources();
    176         boolean includePackageName = resources.getBoolean(R.bool.config_sendPackageName);
    177 
    178         if (sendPackageName && includePackageName) {
    179             String[] packageNameKey =
    180                     {resources.getString(R.string.config_helpPackageNameKey)};
    181             String[] packageNameValue =
    182                     {resources.getString(R.string.config_helpPackageNameValue)};
    183             String intentExtraKey =
    184                     resources.getString(R.string.config_helpIntentExtraKey);
    185             String intentNameKey =
    186                     resources.getString(R.string.config_helpIntentNameKey);
    187             intent.putExtra(intentExtraKey, packageNameKey);
    188             intent.putExtra(intentNameKey, packageNameValue);
    189         }
    190         intent.putExtra(EXTRA_THEME, 1 /* Light, dark action bar */);
    191         TypedArray array = context.obtainStyledAttributes(new int[]{android.R.attr.colorPrimary});
    192         intent.putExtra(EXTRA_PRIMARY_COLOR, array.getColor(0, 0));
    193         array.recycle();
    194     }
    195 
    196     /**
    197      * Adds two query parameters into the Uri, namely the language code and the version code
    198      * of the app's package as gotten via the context.
    199      * @return the uri with added query parameters
    200      */
    201     public static Uri uriWithAddedParameters(Context context, Uri baseUri) {
    202         Uri.Builder builder = baseUri.buildUpon();
    203 
    204         // Add in the preferred language
    205         builder.appendQueryParameter(PARAM_LANGUAGE_CODE, Locale.getDefault().toString());
    206 
    207         // Add in the package version code
    208         if (sCachedVersionCode == null) {
    209             // There is no cached version code, so try to get it from the package manager.
    210             try {
    211                 // cache the version code
    212                 PackageInfo info = context.getPackageManager().getPackageInfo(
    213                         context.getPackageName(), 0);
    214                 sCachedVersionCode = Integer.toString(info.versionCode);
    215 
    216                 // append the version code to the uri
    217                 builder.appendQueryParameter(PARAM_VERSION, sCachedVersionCode);
    218             } catch (NameNotFoundException e) {
    219                 // Cannot find the package name, so don't add in the version parameter
    220                 // This shouldn't happen.
    221                 Log.wtf(TAG, "Invalid package name for context", e);
    222             }
    223         } else {
    224             builder.appendQueryParameter(PARAM_VERSION, sCachedVersionCode);
    225         }
    226 
    227         // Build the full uri and return it
    228         return builder.build();
    229     }
    230 }
    231