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