michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.prompts; michael@0: michael@0: import org.mozilla.gecko.GeckoAppShell; michael@0: import org.mozilla.gecko.util.ThreadUtils; michael@0: import org.mozilla.gecko.widget.GeckoActionProvider; michael@0: michael@0: import android.app.Activity; michael@0: import android.content.ComponentName; michael@0: import android.content.Context; michael@0: import android.content.Intent; michael@0: import android.content.pm.PackageManager; michael@0: import android.content.pm.ResolveInfo; michael@0: import android.widget.ListView; michael@0: import android.util.Log; michael@0: michael@0: import org.json.JSONException; michael@0: import org.json.JSONObject; michael@0: michael@0: import java.util.ArrayList; michael@0: import java.util.List; michael@0: michael@0: /** michael@0: * Shows a prompt letting the user pick from a list of intent handlers for a set of Intents or michael@0: * for a GeckoActionProvider. Basic usage: michael@0: * IntentChooserPrompt prompt = new IntentChooserPrompt(context, new Intent[] { michael@0: * ... // some intents michael@0: * }); michael@0: * prompt.show("Title", context, new IntentHandler() { michael@0: * public void onIntentSelected(Intent intent, int position) { } michael@0: * public void onCancelled() { } michael@0: * }); michael@0: **/ michael@0: public class IntentChooserPrompt { michael@0: private static final String LOGTAG = "GeckoIntentChooser"; michael@0: michael@0: private final ArrayList mItems; michael@0: michael@0: public IntentChooserPrompt(Context context, Intent[] intents) { michael@0: mItems = getItems(context, intents); michael@0: } michael@0: michael@0: public IntentChooserPrompt(Context context, GeckoActionProvider provider) { michael@0: mItems = getItems(context, provider); michael@0: } michael@0: michael@0: /* If an IntentHandler is passed in, will asynchronously call the handler when the dialog is closed michael@0: * Otherwise, will return the Intent that was chosen by the user. Must be called on the UI thread. michael@0: */ michael@0: public void show(final String title, final Context context, final IntentHandler handler) { michael@0: ThreadUtils.assertOnUiThread(); michael@0: michael@0: if (mItems.isEmpty()) { michael@0: Log.i(LOGTAG, "No activities for the intent chooser!"); michael@0: handler.onCancelled(); michael@0: return; michael@0: } michael@0: michael@0: // If there's only one item in the intent list, just return it michael@0: if (mItems.size() == 1) { michael@0: handler.onIntentSelected(mItems.get(0).getIntent(), 0); michael@0: return; michael@0: } michael@0: michael@0: final Prompt prompt = new Prompt(context, new Prompt.PromptCallback() { michael@0: @Override michael@0: public void onPromptFinished(String promptServiceResult) { michael@0: if (handler == null) { michael@0: return; michael@0: } michael@0: michael@0: int itemId = -1; michael@0: try { michael@0: itemId = new JSONObject(promptServiceResult).getInt("button"); michael@0: } catch (JSONException e) { michael@0: Log.e(LOGTAG, "result from promptservice was invalid: ", e); michael@0: } michael@0: michael@0: if (itemId == -1) { michael@0: handler.onCancelled(); michael@0: } else { michael@0: handler.onIntentSelected(mItems.get(itemId).getIntent(), itemId); michael@0: } michael@0: } michael@0: }); michael@0: michael@0: PromptListItem[] arrays = new PromptListItem[mItems.size()]; michael@0: mItems.toArray(arrays); michael@0: prompt.show(title, "", arrays, ListView.CHOICE_MODE_NONE); michael@0: michael@0: return; michael@0: } michael@0: michael@0: // Whether or not any activities were found. Useful for checking if you should try a different Intent set michael@0: public boolean hasActivities(Context context) { michael@0: return mItems.isEmpty(); michael@0: } michael@0: michael@0: // Gets a list of PromptListItems for an Intent array michael@0: private ArrayList getItems(final Context context, Intent[] intents) { michael@0: final ArrayList items = new ArrayList(); michael@0: michael@0: // If we have intents, use them to build the initial list michael@0: for (final Intent intent : intents) { michael@0: items.addAll(getItemsForIntent(context, intent)); michael@0: } michael@0: michael@0: return items; michael@0: } michael@0: michael@0: // Gets a list of PromptListItems for a GeckoActionProvider michael@0: private ArrayList getItems(final Context context, final GeckoActionProvider provider) { michael@0: final ArrayList items = new ArrayList(); michael@0: michael@0: // Add any intents from the provider. michael@0: final PackageManager packageManager = context.getPackageManager(); michael@0: final ArrayList infos = provider.getSortedActivites(); michael@0: michael@0: for (final ResolveInfo info : infos) { michael@0: items.add(getItemForResolveInfo(info, packageManager, provider.getIntent())); michael@0: } michael@0: michael@0: return items; michael@0: } michael@0: michael@0: private PromptListItem getItemForResolveInfo(ResolveInfo info, PackageManager pm, Intent intent) { michael@0: PromptListItem item = new PromptListItem(info.loadLabel(pm).toString()); michael@0: item.setIcon(info.loadIcon(pm)); michael@0: michael@0: Intent i = new Intent(intent); michael@0: // These intents should be implicit. michael@0: i.setComponent(new ComponentName(info.activityInfo.applicationInfo.packageName, michael@0: info.activityInfo.name)); michael@0: item.setIntent(new Intent(i)); michael@0: michael@0: return item; michael@0: } michael@0: michael@0: private ArrayList getItemsForIntent(Context context, Intent intent) { michael@0: ArrayList items = new ArrayList(); michael@0: PackageManager pm = context.getPackageManager(); michael@0: List lri = pm.queryIntentActivityOptions(GeckoAppShell.getGeckoInterface().getActivity().getComponentName(), null, intent, 0); michael@0: michael@0: // If we didn't find any activities, just return the empty list michael@0: if (lri == null) { michael@0: return items; michael@0: } michael@0: michael@0: // Otherwise, convert the ResolveInfo. Note we don't currently check for duplicates here. michael@0: for (ResolveInfo ri : lri) { michael@0: items.add(getItemForResolveInfo(ri, pm, intent)); michael@0: } michael@0: michael@0: return items; michael@0: } michael@0: }