1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/prompts/IntentChooserPrompt.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,159 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.prompts; 1.9 + 1.10 +import org.mozilla.gecko.GeckoAppShell; 1.11 +import org.mozilla.gecko.util.ThreadUtils; 1.12 +import org.mozilla.gecko.widget.GeckoActionProvider; 1.13 + 1.14 +import android.app.Activity; 1.15 +import android.content.ComponentName; 1.16 +import android.content.Context; 1.17 +import android.content.Intent; 1.18 +import android.content.pm.PackageManager; 1.19 +import android.content.pm.ResolveInfo; 1.20 +import android.widget.ListView; 1.21 +import android.util.Log; 1.22 + 1.23 +import org.json.JSONException; 1.24 +import org.json.JSONObject; 1.25 + 1.26 +import java.util.ArrayList; 1.27 +import java.util.List; 1.28 + 1.29 +/** 1.30 + * Shows a prompt letting the user pick from a list of intent handlers for a set of Intents or 1.31 + * for a GeckoActionProvider. Basic usage: 1.32 + * IntentChooserPrompt prompt = new IntentChooserPrompt(context, new Intent[] { 1.33 + * ... // some intents 1.34 + * }); 1.35 + * prompt.show("Title", context, new IntentHandler() { 1.36 + * public void onIntentSelected(Intent intent, int position) { } 1.37 + * public void onCancelled() { } 1.38 + * }); 1.39 + **/ 1.40 +public class IntentChooserPrompt { 1.41 + private static final String LOGTAG = "GeckoIntentChooser"; 1.42 + 1.43 + private final ArrayList<PromptListItem> mItems; 1.44 + 1.45 + public IntentChooserPrompt(Context context, Intent[] intents) { 1.46 + mItems = getItems(context, intents); 1.47 + } 1.48 + 1.49 + public IntentChooserPrompt(Context context, GeckoActionProvider provider) { 1.50 + mItems = getItems(context, provider); 1.51 + } 1.52 + 1.53 + /* If an IntentHandler is passed in, will asynchronously call the handler when the dialog is closed 1.54 + * Otherwise, will return the Intent that was chosen by the user. Must be called on the UI thread. 1.55 + */ 1.56 + public void show(final String title, final Context context, final IntentHandler handler) { 1.57 + ThreadUtils.assertOnUiThread(); 1.58 + 1.59 + if (mItems.isEmpty()) { 1.60 + Log.i(LOGTAG, "No activities for the intent chooser!"); 1.61 + handler.onCancelled(); 1.62 + return; 1.63 + } 1.64 + 1.65 + // If there's only one item in the intent list, just return it 1.66 + if (mItems.size() == 1) { 1.67 + handler.onIntentSelected(mItems.get(0).getIntent(), 0); 1.68 + return; 1.69 + } 1.70 + 1.71 + final Prompt prompt = new Prompt(context, new Prompt.PromptCallback() { 1.72 + @Override 1.73 + public void onPromptFinished(String promptServiceResult) { 1.74 + if (handler == null) { 1.75 + return; 1.76 + } 1.77 + 1.78 + int itemId = -1; 1.79 + try { 1.80 + itemId = new JSONObject(promptServiceResult).getInt("button"); 1.81 + } catch (JSONException e) { 1.82 + Log.e(LOGTAG, "result from promptservice was invalid: ", e); 1.83 + } 1.84 + 1.85 + if (itemId == -1) { 1.86 + handler.onCancelled(); 1.87 + } else { 1.88 + handler.onIntentSelected(mItems.get(itemId).getIntent(), itemId); 1.89 + } 1.90 + } 1.91 + }); 1.92 + 1.93 + PromptListItem[] arrays = new PromptListItem[mItems.size()]; 1.94 + mItems.toArray(arrays); 1.95 + prompt.show(title, "", arrays, ListView.CHOICE_MODE_NONE); 1.96 + 1.97 + return; 1.98 + } 1.99 + 1.100 + // Whether or not any activities were found. Useful for checking if you should try a different Intent set 1.101 + public boolean hasActivities(Context context) { 1.102 + return mItems.isEmpty(); 1.103 + } 1.104 + 1.105 + // Gets a list of PromptListItems for an Intent array 1.106 + private ArrayList<PromptListItem> getItems(final Context context, Intent[] intents) { 1.107 + final ArrayList<PromptListItem> items = new ArrayList<PromptListItem>(); 1.108 + 1.109 + // If we have intents, use them to build the initial list 1.110 + for (final Intent intent : intents) { 1.111 + items.addAll(getItemsForIntent(context, intent)); 1.112 + } 1.113 + 1.114 + return items; 1.115 + } 1.116 + 1.117 + // Gets a list of PromptListItems for a GeckoActionProvider 1.118 + private ArrayList<PromptListItem> getItems(final Context context, final GeckoActionProvider provider) { 1.119 + final ArrayList<PromptListItem> items = new ArrayList<PromptListItem>(); 1.120 + 1.121 + // Add any intents from the provider. 1.122 + final PackageManager packageManager = context.getPackageManager(); 1.123 + final ArrayList<ResolveInfo> infos = provider.getSortedActivites(); 1.124 + 1.125 + for (final ResolveInfo info : infos) { 1.126 + items.add(getItemForResolveInfo(info, packageManager, provider.getIntent())); 1.127 + } 1.128 + 1.129 + return items; 1.130 + } 1.131 + 1.132 + private PromptListItem getItemForResolveInfo(ResolveInfo info, PackageManager pm, Intent intent) { 1.133 + PromptListItem item = new PromptListItem(info.loadLabel(pm).toString()); 1.134 + item.setIcon(info.loadIcon(pm)); 1.135 + 1.136 + Intent i = new Intent(intent); 1.137 + // These intents should be implicit. 1.138 + i.setComponent(new ComponentName(info.activityInfo.applicationInfo.packageName, 1.139 + info.activityInfo.name)); 1.140 + item.setIntent(new Intent(i)); 1.141 + 1.142 + return item; 1.143 + } 1.144 + 1.145 + private ArrayList<PromptListItem> getItemsForIntent(Context context, Intent intent) { 1.146 + ArrayList<PromptListItem> items = new ArrayList<PromptListItem>(); 1.147 + PackageManager pm = context.getPackageManager(); 1.148 + List<ResolveInfo> lri = pm.queryIntentActivityOptions(GeckoAppShell.getGeckoInterface().getActivity().getComponentName(), null, intent, 0); 1.149 + 1.150 + // If we didn't find any activities, just return the empty list 1.151 + if (lri == null) { 1.152 + return items; 1.153 + } 1.154 + 1.155 + // Otherwise, convert the ResolveInfo. Note we don't currently check for duplicates here. 1.156 + for (ResolveInfo ri : lri) { 1.157 + items.add(getItemForResolveInfo(ri, pm, intent)); 1.158 + } 1.159 + 1.160 + return items; 1.161 + } 1.162 +}