michael@0: /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- 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 michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.widget; michael@0: michael@0: import org.mozilla.gecko.GeckoAppShell; michael@0: import org.mozilla.gecko.Telemetry; michael@0: import org.mozilla.gecko.TelemetryContract; michael@0: import org.mozilla.gecko.menu.MenuItemActionView; michael@0: import org.mozilla.gecko.util.ThreadUtils; michael@0: 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.graphics.drawable.Drawable; michael@0: import android.view.MenuItem; michael@0: import android.view.MenuItem.OnMenuItemClickListener; michael@0: import android.view.SubMenu; michael@0: import android.view.View; michael@0: import android.view.View.OnClickListener; michael@0: import android.text.TextUtils; michael@0: michael@0: import java.util.ArrayList; michael@0: import java.util.HashMap; michael@0: michael@0: public class GeckoActionProvider { michael@0: private static int MAX_HISTORY_SIZE = 2; michael@0: michael@0: /** michael@0: * A listener to know when a target was selected. michael@0: * When setting a provider, the activity can listen to this, michael@0: * to close the menu. michael@0: */ michael@0: public interface OnTargetSelectedListener { michael@0: public void onTargetSelected(); michael@0: } michael@0: michael@0: private final Context mContext; michael@0: michael@0: public final static String DEFAULT_MIME_TYPE = "text/plain"; michael@0: michael@0: public static final String DEFAULT_HISTORY_FILE_NAME = "history.xml"; michael@0: michael@0: // History file. michael@0: private String mHistoryFileName = DEFAULT_HISTORY_FILE_NAME; michael@0: michael@0: private OnTargetSelectedListener mOnTargetListener; michael@0: michael@0: private final Callbacks mCallbacks = new Callbacks(); michael@0: michael@0: private static HashMap mProviders = new HashMap(); michael@0: michael@0: private static String getFilenameFromMimeType(String mimeType) { michael@0: String[] mime = mimeType.split("/"); michael@0: michael@0: // All text mimetypes use the default provider michael@0: if ("text".equals(mime[0])) { michael@0: return DEFAULT_HISTORY_FILE_NAME; michael@0: } michael@0: michael@0: return "history-" + mime[0] + ".xml"; michael@0: } michael@0: michael@0: // Gets the action provider for a particular mimetype michael@0: public static GeckoActionProvider getForType(String mimeType, Context context) { michael@0: if (!mProviders.keySet().contains(mimeType)) { michael@0: GeckoActionProvider provider = new GeckoActionProvider(context); michael@0: michael@0: // For empty types, we just return a default provider michael@0: if (TextUtils.isEmpty(mimeType)) { michael@0: return provider; michael@0: } michael@0: michael@0: provider.setHistoryFileName(getFilenameFromMimeType(mimeType)); michael@0: mProviders.put(mimeType, provider); michael@0: } michael@0: return mProviders.get(mimeType); michael@0: } michael@0: michael@0: public GeckoActionProvider(Context context) { michael@0: mContext = context; michael@0: } michael@0: michael@0: public View onCreateActionView() { michael@0: // Create the view and set its data model. michael@0: ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); michael@0: MenuItemActionView view = new MenuItemActionView(mContext, null); michael@0: view.addActionButtonClickListener(mCallbacks); michael@0: michael@0: final PackageManager packageManager = mContext.getPackageManager(); michael@0: int historySize = dataModel.getDistinctActivityCountInHistory(); michael@0: if (historySize > MAX_HISTORY_SIZE) { michael@0: historySize = MAX_HISTORY_SIZE; michael@0: } michael@0: michael@0: // Historical data is dependent on past selection of activities. michael@0: // Activity count is determined by the number of activities that can handle michael@0: // the particular intent. When no intent is set, the activity count is 0, michael@0: // while the history count can be a valid number. michael@0: if (historySize > dataModel.getActivityCount()) { michael@0: return view; michael@0: } michael@0: michael@0: for (int i = 0; i < historySize; i++) { michael@0: view.addActionButton(dataModel.getActivity(i).loadIcon(packageManager)); michael@0: } michael@0: michael@0: return view; michael@0: } michael@0: michael@0: public View getView() { michael@0: return onCreateActionView(); michael@0: } michael@0: michael@0: public boolean hasSubMenu() { michael@0: return true; michael@0: } michael@0: michael@0: public void onPrepareSubMenu(SubMenu subMenu) { michael@0: // Clear since the order of items may change. michael@0: subMenu.clear(); michael@0: michael@0: ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); michael@0: PackageManager packageManager = mContext.getPackageManager(); michael@0: michael@0: // Populate the sub-menu with a sub set of the activities. michael@0: final int count = dataModel.getActivityCount(); michael@0: for (int i = 0; i < count; i++) { michael@0: ResolveInfo activity = dataModel.getActivity(i); michael@0: subMenu.add(0, i, i, activity.loadLabel(packageManager)) michael@0: .setIcon(activity.loadIcon(packageManager)) michael@0: .setOnMenuItemClickListener(mCallbacks); michael@0: } michael@0: } michael@0: michael@0: public void setHistoryFileName(String historyFile) { michael@0: mHistoryFileName = historyFile; michael@0: } michael@0: michael@0: public Intent getIntent() { michael@0: ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); michael@0: return dataModel.getIntent(); michael@0: } michael@0: michael@0: public void setIntent(Intent intent) { michael@0: ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); michael@0: dataModel.setIntent(intent); michael@0: michael@0: // Inform the target listener to refresh it's UI, if needed. michael@0: if (mOnTargetListener != null) { michael@0: mOnTargetListener.onTargetSelected(); michael@0: } michael@0: } michael@0: michael@0: public void setOnTargetSelectedListener(OnTargetSelectedListener listener) { michael@0: mOnTargetListener = listener; michael@0: } michael@0: michael@0: public ArrayList getSortedActivites() { michael@0: ArrayList infos = new ArrayList(); michael@0: michael@0: ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); michael@0: PackageManager packageManager = mContext.getPackageManager(); michael@0: michael@0: // Populate the sub-menu with a sub set of the activities. michael@0: final int count = dataModel.getActivityCount(); michael@0: for (int i = 0; i < count; i++) { michael@0: infos.add(dataModel.getActivity(i)); michael@0: } michael@0: return infos; michael@0: } michael@0: michael@0: public void chooseActivity(int position) { michael@0: mCallbacks.chooseActivity(position); michael@0: } michael@0: michael@0: /** michael@0: * Listener for handling default activity / menu item clicks. michael@0: */ michael@0: private class Callbacks implements OnMenuItemClickListener, michael@0: OnClickListener { michael@0: private void chooseActivity(int index) { michael@0: final ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); michael@0: final Intent launchIntent = dataModel.chooseActivity(index); michael@0: if (launchIntent != null) { michael@0: // This may cause a download to happen. Make sure we're on the background thread. michael@0: ThreadUtils.postToBackgroundThread(new Runnable() { michael@0: @Override michael@0: public void run() { michael@0: // Share image downloads the image before sharing it. michael@0: String type = launchIntent.getType(); michael@0: if (Intent.ACTION_SEND.equals(launchIntent.getAction()) && type != null && type.startsWith("image/")) { michael@0: GeckoAppShell.downloadImageForIntent(launchIntent); michael@0: } michael@0: michael@0: launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); michael@0: mContext.startActivity(launchIntent); michael@0: } michael@0: }); michael@0: } michael@0: michael@0: if (mOnTargetListener != null) { michael@0: mOnTargetListener.onTargetSelected(); michael@0: } michael@0: } michael@0: michael@0: @Override michael@0: public boolean onMenuItemClick(MenuItem item) { michael@0: chooseActivity(item.getItemId()); michael@0: michael@0: // Context: Sharing via chrome mainmenu list (no explicit session is active) michael@0: Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST); michael@0: return true; michael@0: } michael@0: michael@0: @Override michael@0: public void onClick(View view) { michael@0: Integer index = (Integer) view.getTag(); michael@0: chooseActivity(index); michael@0: michael@0: // Context: Sharing via chrome mainmenu and content contextmenu quickshare (no explicit session is active) michael@0: Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.BUTTON); michael@0: } michael@0: } michael@0: }