1aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani/* 2aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * Copyright (C) 2012 The Android Open Source Project 3aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * 4aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * Licensed under the Apache License, Version 2.0 (the "License"); 5aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * you may not use this file except in compliance with the License. 6aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * You may obtain a copy of the License at 7aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * 8aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * http://www.apache.org/licenses/LICENSE-2.0 9aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * 10aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * Unless required by applicable law or agreed to in writing, software 11aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * distributed under the License is distributed on an "AS IS" BASIS, 12aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * See the License for the specific language governing permissions and 14aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * limitations under the License. 15aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani */ 16aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 17aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasanipackage com.android.settings; 18aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 196e61347242ea8d9ac0645b2669f222696c65eec6Jason Monkimport android.app.Activity; 2066d879ce9ffe4411184d54795f8adf5e7fe8cfecLifu Tangimport android.content.ComponentName; 21aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasaniimport android.content.Context; 22aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasaniimport android.content.Intent; 23aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasaniimport android.content.pm.PackageInfo; 24aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasaniimport android.content.pm.PackageManager.NameNotFoundException; 2515dcebe1e79ad396a08873f940e2f33d432cf387Jason Monkimport android.content.res.Resources.Theme; 26aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasaniimport android.net.Uri; 27aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasaniimport android.text.TextUtils; 28aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasaniimport android.util.Log; 2915dcebe1e79ad396a08873f940e2f33d432cf387Jason Monkimport android.util.TypedValue; 3023acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monkimport android.view.Menu; 31aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasaniimport android.view.MenuItem; 326e61347242ea8d9ac0645b2669f222696c65eec6Jason Monkimport android.view.MenuItem.OnMenuItemClickListener; 33aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 3423acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monkimport java.net.URISyntaxException; 35aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasaniimport java.util.Locale; 36aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 37aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani/** 38aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * Functions to easily prepare contextual help menu option items with an intent that opens up the 39aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * browser to a particular URL, while taking into account the preferred language and app version. 40aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani */ 41aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasanipublic class HelpUtils { 4223acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk private final static String TAG = HelpUtils.class.getSimpleName(); 4323acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk 4423acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk private static final int MENU_HELP = Menu.FIRST + 100; 45aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 46aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani /** 47aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * Help URL query parameter key for the preferred language. 48aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani */ 49aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani private final static String PARAM_LANGUAGE_CODE = "hl"; 50aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 51aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani /** 52aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * Help URL query parameter key for the app version. 53aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani */ 54aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani private final static String PARAM_VERSION = "version"; 55aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 5615dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk // Constants for help intents. 5715dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk private static final String EXTRA_CONTEXT = "EXTRA_CONTEXT"; 5815dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk private static final String EXTRA_THEME = "EXTRA_THEME"; 5915dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk private static final String EXTRA_PRIMARY_COLOR = "EXTRA_PRIMARY_COLOR"; 6015dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk private static final String EXTRA_BACKUP_URI = "EXTRA_BACKUP_URI"; 6115dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk 62aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani /** 63aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * Cached version code to prevent repeated calls to the package manager. 64aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani */ 65aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani private static String sCachedVersionCode = null; 66aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 67aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani /** Static helper that is not instantiable*/ 68aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani private HelpUtils() { } 69aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 706e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk public static boolean prepareHelpMenuItem(Activity activity, Menu menu, String helpUri, 7115dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk String backupContext) { 7223acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk MenuItem helpItem = menu.add(0, MENU_HELP, 0, R.string.help_label); 736e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk return prepareHelpMenuItem(activity, helpItem, helpUri, backupContext); 7423acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk } 7523acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk 766e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk public static boolean prepareHelpMenuItem(Activity activity, Menu menu, int helpUriResource, 7715dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk String backupContext) { 7823acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk MenuItem helpItem = menu.add(0, MENU_HELP, 0, R.string.help_label); 796e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk return prepareHelpMenuItem(activity, helpItem, activity.getString(helpUriResource), 8015dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk backupContext); 81aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani } 82aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 83aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani /** 84aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * Prepares the help menu item by doing the following. 85aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * - If the helpUrlString is empty or null, the help menu item is made invisible. 86aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * - Otherwise, this makes the help menu item visible and sets the intent for the help menu 87aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * item to view the URL. 88aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * 89aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * @return returns whether the help menu item has been made visible. 90aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani */ 916e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk public static boolean prepareHelpMenuItem(final Activity activity, MenuItem helpMenuItem, 9215dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk String helpUriString, String backupContext) { 9323acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk if (TextUtils.isEmpty(helpUriString)) { 94aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // The help url string is empty or null, so set the help menu item to be invisible. 95aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani helpMenuItem.setVisible(false); 96aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 97aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // return that the help menu item is not visible (i.e. false) 98aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani return false; 99aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani } else { 1006e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk final Intent intent = getHelpIntent(activity, helpUriString, backupContext); 101aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 102aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // Set the intent to the help menu item, show the help menu item in the overflow 103aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // menu, and make it visible. 10415dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk if (intent != null) { 1056e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk helpMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() { 1066e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk @Override 1076e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk public boolean onMenuItemClick(MenuItem item) { 1086e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk activity.startActivityForResult(intent, 0); 1096e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk return true; 1106e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk } 1116e61347242ea8d9ac0645b2669f222696c65eec6Jason Monk }); 11266d879ce9ffe4411184d54795f8adf5e7fe8cfecLifu Tang helpMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 11366d879ce9ffe4411184d54795f8adf5e7fe8cfecLifu Tang helpMenuItem.setVisible(true); 11466d879ce9ffe4411184d54795f8adf5e7fe8cfecLifu Tang } else { 11566d879ce9ffe4411184d54795f8adf5e7fe8cfecLifu Tang helpMenuItem.setVisible(false); 11666d879ce9ffe4411184d54795f8adf5e7fe8cfecLifu Tang return false; 11766d879ce9ffe4411184d54795f8adf5e7fe8cfecLifu Tang } 118aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 119aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // return that the help menu item is visible (i.e., true) 120aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani return true; 121aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani } 122aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani } 123aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 12415dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk public static Intent getHelpIntent(Context context, String helpUriString, 12515dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk String backupContext) { 12623acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk // Try to handle as Intent Uri, otherwise just treat as Uri. 12723acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk try { 12815dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk Intent intent = Intent.parseUri(helpUriString, 12923acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk Intent.URI_ANDROID_APP_SCHEME | Intent.URI_INTENT_SCHEME); 13015dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk addIntentParameters(context, intent, backupContext); 13115dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk ComponentName component = intent.resolveActivity(context.getPackageManager()); 13215dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk if (component != null) { 13315dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk return intent; 13415dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk } else if (intent.hasExtra(EXTRA_BACKUP_URI)) { 13515dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk // This extra contains a backup URI for when the intent isn't available. 13615dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk return getHelpIntent(context, intent.getStringExtra(EXTRA_BACKUP_URI), 13715dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk backupContext); 13815dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk } else { 13915dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk return null; 14015dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk } 14123acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk } catch (URISyntaxException e) { 14223acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk } 14323acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk // The help url string exists, so first add in some extra query parameters. 14423acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk final Uri fullUri = uriWithAddedParameters(context, Uri.parse(helpUriString)); 14523acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk 14623acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk // Then, create an intent that will be fired when the user 14723acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk // selects this help menu item. 14823acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk Intent intent = new Intent(Intent.ACTION_VIEW, fullUri); 14923acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 15023acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 15123acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk return intent; 15223acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk } 15323acc2bb8af7da000d72a8c1d8c28a2792200348Jason Monk 15415dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk private static void addIntentParameters(Context context, Intent intent, String backupContext) { 15515dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk if (!intent.hasExtra(EXTRA_CONTEXT)) { 15615dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk // Insert some context if none exists. 15715dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk intent.putExtra(EXTRA_CONTEXT, backupContext); 15815dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk } 15915dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk intent.putExtra(EXTRA_THEME, 1 /* Light, dark action bar */); 16015dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk Theme theme = context.getTheme(); 16115dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk TypedValue typedValue = new TypedValue(); 16215dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk theme.resolveAttribute(android.R.attr.colorPrimary, typedValue, true); 16315dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk intent.putExtra(EXTRA_PRIMARY_COLOR, context.getColor(typedValue.resourceId)); 16415dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk } 16515dcebe1e79ad396a08873f940e2f33d432cf387Jason Monk 166aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani /** 167aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * Adds two query parameters into the Uri, namely the language code and the version code 168aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * of the app's package as gotten via the context. 169aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani * @return the uri with added query parameters 170aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani */ 171b412e18296cf3958585efdaec15c8b9d28bd2c50Martijn Coenen public static Uri uriWithAddedParameters(Context context, Uri baseUri) { 172aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani Uri.Builder builder = baseUri.buildUpon(); 173aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 174aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // Add in the preferred language 175aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani builder.appendQueryParameter(PARAM_LANGUAGE_CODE, Locale.getDefault().toString()); 176aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 177aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // Add in the package version code 178aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani if (sCachedVersionCode == null) { 179aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // There is no cached version code, so try to get it from the package manager. 180aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani try { 181aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // cache the version code 182aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani PackageInfo info = context.getPackageManager().getPackageInfo( 183aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani context.getPackageName(), 0); 184aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani sCachedVersionCode = Integer.toString(info.versionCode); 185aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 186aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // append the version code to the uri 187aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani builder.appendQueryParameter(PARAM_VERSION, sCachedVersionCode); 188aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani } catch (NameNotFoundException e) { 189aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // Cannot find the package name, so don't add in the version parameter 190aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // This shouldn't happen. 191aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani Log.wtf(TAG, "Invalid package name for context", e); 192aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani } 193aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani } else { 194aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani builder.appendQueryParameter(PARAM_VERSION, sCachedVersionCode); 195aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani } 196aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani 197aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani // Build the full uri and return it 198aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani return builder.build(); 199aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani } 200aeb57edaef1abdcdcd21eb443047386940ffb755Amith Yamasani} 201