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