|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 package org.mozilla.gecko.prompts; |
|
6 |
|
7 import org.mozilla.gecko.GeckoAppShell; |
|
8 import org.mozilla.gecko.util.ThreadUtils; |
|
9 import org.mozilla.gecko.widget.GeckoActionProvider; |
|
10 |
|
11 import android.app.Activity; |
|
12 import android.content.ComponentName; |
|
13 import android.content.Context; |
|
14 import android.content.Intent; |
|
15 import android.content.pm.PackageManager; |
|
16 import android.content.pm.ResolveInfo; |
|
17 import android.widget.ListView; |
|
18 import android.util.Log; |
|
19 |
|
20 import org.json.JSONException; |
|
21 import org.json.JSONObject; |
|
22 |
|
23 import java.util.ArrayList; |
|
24 import java.util.List; |
|
25 |
|
26 /** |
|
27 * Shows a prompt letting the user pick from a list of intent handlers for a set of Intents or |
|
28 * for a GeckoActionProvider. Basic usage: |
|
29 * IntentChooserPrompt prompt = new IntentChooserPrompt(context, new Intent[] { |
|
30 * ... // some intents |
|
31 * }); |
|
32 * prompt.show("Title", context, new IntentHandler() { |
|
33 * public void onIntentSelected(Intent intent, int position) { } |
|
34 * public void onCancelled() { } |
|
35 * }); |
|
36 **/ |
|
37 public class IntentChooserPrompt { |
|
38 private static final String LOGTAG = "GeckoIntentChooser"; |
|
39 |
|
40 private final ArrayList<PromptListItem> mItems; |
|
41 |
|
42 public IntentChooserPrompt(Context context, Intent[] intents) { |
|
43 mItems = getItems(context, intents); |
|
44 } |
|
45 |
|
46 public IntentChooserPrompt(Context context, GeckoActionProvider provider) { |
|
47 mItems = getItems(context, provider); |
|
48 } |
|
49 |
|
50 /* If an IntentHandler is passed in, will asynchronously call the handler when the dialog is closed |
|
51 * Otherwise, will return the Intent that was chosen by the user. Must be called on the UI thread. |
|
52 */ |
|
53 public void show(final String title, final Context context, final IntentHandler handler) { |
|
54 ThreadUtils.assertOnUiThread(); |
|
55 |
|
56 if (mItems.isEmpty()) { |
|
57 Log.i(LOGTAG, "No activities for the intent chooser!"); |
|
58 handler.onCancelled(); |
|
59 return; |
|
60 } |
|
61 |
|
62 // If there's only one item in the intent list, just return it |
|
63 if (mItems.size() == 1) { |
|
64 handler.onIntentSelected(mItems.get(0).getIntent(), 0); |
|
65 return; |
|
66 } |
|
67 |
|
68 final Prompt prompt = new Prompt(context, new Prompt.PromptCallback() { |
|
69 @Override |
|
70 public void onPromptFinished(String promptServiceResult) { |
|
71 if (handler == null) { |
|
72 return; |
|
73 } |
|
74 |
|
75 int itemId = -1; |
|
76 try { |
|
77 itemId = new JSONObject(promptServiceResult).getInt("button"); |
|
78 } catch (JSONException e) { |
|
79 Log.e(LOGTAG, "result from promptservice was invalid: ", e); |
|
80 } |
|
81 |
|
82 if (itemId == -1) { |
|
83 handler.onCancelled(); |
|
84 } else { |
|
85 handler.onIntentSelected(mItems.get(itemId).getIntent(), itemId); |
|
86 } |
|
87 } |
|
88 }); |
|
89 |
|
90 PromptListItem[] arrays = new PromptListItem[mItems.size()]; |
|
91 mItems.toArray(arrays); |
|
92 prompt.show(title, "", arrays, ListView.CHOICE_MODE_NONE); |
|
93 |
|
94 return; |
|
95 } |
|
96 |
|
97 // Whether or not any activities were found. Useful for checking if you should try a different Intent set |
|
98 public boolean hasActivities(Context context) { |
|
99 return mItems.isEmpty(); |
|
100 } |
|
101 |
|
102 // Gets a list of PromptListItems for an Intent array |
|
103 private ArrayList<PromptListItem> getItems(final Context context, Intent[] intents) { |
|
104 final ArrayList<PromptListItem> items = new ArrayList<PromptListItem>(); |
|
105 |
|
106 // If we have intents, use them to build the initial list |
|
107 for (final Intent intent : intents) { |
|
108 items.addAll(getItemsForIntent(context, intent)); |
|
109 } |
|
110 |
|
111 return items; |
|
112 } |
|
113 |
|
114 // Gets a list of PromptListItems for a GeckoActionProvider |
|
115 private ArrayList<PromptListItem> getItems(final Context context, final GeckoActionProvider provider) { |
|
116 final ArrayList<PromptListItem> items = new ArrayList<PromptListItem>(); |
|
117 |
|
118 // Add any intents from the provider. |
|
119 final PackageManager packageManager = context.getPackageManager(); |
|
120 final ArrayList<ResolveInfo> infos = provider.getSortedActivites(); |
|
121 |
|
122 for (final ResolveInfo info : infos) { |
|
123 items.add(getItemForResolveInfo(info, packageManager, provider.getIntent())); |
|
124 } |
|
125 |
|
126 return items; |
|
127 } |
|
128 |
|
129 private PromptListItem getItemForResolveInfo(ResolveInfo info, PackageManager pm, Intent intent) { |
|
130 PromptListItem item = new PromptListItem(info.loadLabel(pm).toString()); |
|
131 item.setIcon(info.loadIcon(pm)); |
|
132 |
|
133 Intent i = new Intent(intent); |
|
134 // These intents should be implicit. |
|
135 i.setComponent(new ComponentName(info.activityInfo.applicationInfo.packageName, |
|
136 info.activityInfo.name)); |
|
137 item.setIntent(new Intent(i)); |
|
138 |
|
139 return item; |
|
140 } |
|
141 |
|
142 private ArrayList<PromptListItem> getItemsForIntent(Context context, Intent intent) { |
|
143 ArrayList<PromptListItem> items = new ArrayList<PromptListItem>(); |
|
144 PackageManager pm = context.getPackageManager(); |
|
145 List<ResolveInfo> lri = pm.queryIntentActivityOptions(GeckoAppShell.getGeckoInterface().getActivity().getComponentName(), null, intent, 0); |
|
146 |
|
147 // If we didn't find any activities, just return the empty list |
|
148 if (lri == null) { |
|
149 return items; |
|
150 } |
|
151 |
|
152 // Otherwise, convert the ResolveInfo. Note we don't currently check for duplicates here. |
|
153 for (ResolveInfo ri : lri) { |
|
154 items.add(getItemForResolveInfo(ri, pm, intent)); |
|
155 } |
|
156 |
|
157 return items; |
|
158 } |
|
159 } |