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