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 17package com.android.settings; 18 19import android.app.Activity; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.Intent; 23import android.content.pm.PackageInfo; 24import android.content.pm.PackageManager.NameNotFoundException; 25import android.content.res.Resources.Theme; 26import android.net.Uri; 27import android.text.TextUtils; 28import android.util.Log; 29import android.util.TypedValue; 30import android.view.Menu; 31import android.view.MenuItem; 32import android.view.MenuItem.OnMenuItemClickListener; 33 34import java.net.URISyntaxException; 35import java.util.Locale; 36 37/** 38 * Functions to easily prepare contextual help menu option items with an intent that opens up the 39 * browser to a particular URL, while taking into account the preferred language and app version. 40 */ 41public class HelpUtils { 42 private final static String TAG = HelpUtils.class.getSimpleName(); 43 44 private static final int MENU_HELP = Menu.FIRST + 100; 45 46 /** 47 * Help URL query parameter key for the preferred language. 48 */ 49 private final static String PARAM_LANGUAGE_CODE = "hl"; 50 51 /** 52 * Help URL query parameter key for the app version. 53 */ 54 private final static String PARAM_VERSION = "version"; 55 56 // Constants for help intents. 57 private static final String EXTRA_CONTEXT = "EXTRA_CONTEXT"; 58 private static final String EXTRA_THEME = "EXTRA_THEME"; 59 private static final String EXTRA_PRIMARY_COLOR = "EXTRA_PRIMARY_COLOR"; 60 private static final String EXTRA_BACKUP_URI = "EXTRA_BACKUP_URI"; 61 62 /** 63 * Cached version code to prevent repeated calls to the package manager. 64 */ 65 private static String sCachedVersionCode = null; 66 67 /** Static helper that is not instantiable*/ 68 private HelpUtils() { } 69 70 public static boolean prepareHelpMenuItem(Activity activity, Menu menu, String helpUri, 71 String backupContext) { 72 MenuItem helpItem = menu.add(0, MENU_HELP, 0, R.string.help_label); 73 return prepareHelpMenuItem(activity, helpItem, helpUri, backupContext); 74 } 75 76 public static boolean prepareHelpMenuItem(Activity activity, Menu menu, int helpUriResource, 77 String backupContext) { 78 MenuItem helpItem = menu.add(0, MENU_HELP, 0, R.string.help_label); 79 return prepareHelpMenuItem(activity, helpItem, activity.getString(helpUriResource), 80 backupContext); 81 } 82 83 /** 84 * Prepares the help menu item by doing the following. 85 * - If the helpUrlString is empty or null, the help menu item is made invisible. 86 * - Otherwise, this makes the help menu item visible and sets the intent for the help menu 87 * item to view the URL. 88 * 89 * @return returns whether the help menu item has been made visible. 90 */ 91 public static boolean prepareHelpMenuItem(final Activity activity, MenuItem helpMenuItem, 92 String helpUriString, String backupContext) { 93 if (TextUtils.isEmpty(helpUriString)) { 94 // The help url string is empty or null, so set the help menu item to be invisible. 95 helpMenuItem.setVisible(false); 96 97 // return that the help menu item is not visible (i.e. false) 98 return false; 99 } else { 100 final Intent intent = getHelpIntent(activity, helpUriString, backupContext); 101 102 // Set the intent to the help menu item, show the help menu item in the overflow 103 // menu, and make it visible. 104 if (intent != null) { 105 helpMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() { 106 @Override 107 public boolean onMenuItemClick(MenuItem item) { 108 activity.startActivityForResult(intent, 0); 109 return true; 110 } 111 }); 112 helpMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 113 helpMenuItem.setVisible(true); 114 } else { 115 helpMenuItem.setVisible(false); 116 return false; 117 } 118 119 // return that the help menu item is visible (i.e., true) 120 return true; 121 } 122 } 123 124 public static Intent getHelpIntent(Context context, String helpUriString, 125 String backupContext) { 126 // Try to handle as Intent Uri, otherwise just treat as Uri. 127 try { 128 Intent intent = Intent.parseUri(helpUriString, 129 Intent.URI_ANDROID_APP_SCHEME | Intent.URI_INTENT_SCHEME); 130 addIntentParameters(context, intent, backupContext); 131 ComponentName component = intent.resolveActivity(context.getPackageManager()); 132 if (component != null) { 133 return intent; 134 } else if (intent.hasExtra(EXTRA_BACKUP_URI)) { 135 // This extra contains a backup URI for when the intent isn't available. 136 return getHelpIntent(context, intent.getStringExtra(EXTRA_BACKUP_URI), 137 backupContext); 138 } else { 139 return null; 140 } 141 } catch (URISyntaxException e) { 142 } 143 // The help url string exists, so first add in some extra query parameters. 144 final Uri fullUri = uriWithAddedParameters(context, Uri.parse(helpUriString)); 145 146 // Then, create an intent that will be fired when the user 147 // selects this help menu item. 148 Intent intent = new Intent(Intent.ACTION_VIEW, fullUri); 149 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 150 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 151 return intent; 152 } 153 154 private static void addIntentParameters(Context context, Intent intent, String backupContext) { 155 if (!intent.hasExtra(EXTRA_CONTEXT)) { 156 // Insert some context if none exists. 157 intent.putExtra(EXTRA_CONTEXT, backupContext); 158 } 159 intent.putExtra(EXTRA_THEME, 1 /* Light, dark action bar */); 160 Theme theme = context.getTheme(); 161 TypedValue typedValue = new TypedValue(); 162 theme.resolveAttribute(android.R.attr.colorPrimary, typedValue, true); 163 intent.putExtra(EXTRA_PRIMARY_COLOR, context.getColor(typedValue.resourceId)); 164 } 165 166 /** 167 * Adds two query parameters into the Uri, namely the language code and the version code 168 * of the app's package as gotten via the context. 169 * @return the uri with added query parameters 170 */ 171 public static Uri uriWithAddedParameters(Context context, Uri baseUri) { 172 Uri.Builder builder = baseUri.buildUpon(); 173 174 // Add in the preferred language 175 builder.appendQueryParameter(PARAM_LANGUAGE_CODE, Locale.getDefault().toString()); 176 177 // Add in the package version code 178 if (sCachedVersionCode == null) { 179 // There is no cached version code, so try to get it from the package manager. 180 try { 181 // cache the version code 182 PackageInfo info = context.getPackageManager().getPackageInfo( 183 context.getPackageName(), 0); 184 sCachedVersionCode = Integer.toString(info.versionCode); 185 186 // append the version code to the uri 187 builder.appendQueryParameter(PARAM_VERSION, sCachedVersionCode); 188 } catch (NameNotFoundException e) { 189 // Cannot find the package name, so don't add in the version parameter 190 // This shouldn't happen. 191 Log.wtf(TAG, "Invalid package name for context", e); 192 } 193 } else { 194 builder.appendQueryParameter(PARAM_VERSION, sCachedVersionCode); 195 } 196 197 // Build the full uri and return it 198 return builder.build(); 199 } 200} 201