1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/widget/GeckoActionProvider.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,228 @@ 1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +package org.mozilla.gecko.widget; 1.10 + 1.11 +import org.mozilla.gecko.GeckoAppShell; 1.12 +import org.mozilla.gecko.Telemetry; 1.13 +import org.mozilla.gecko.TelemetryContract; 1.14 +import org.mozilla.gecko.menu.MenuItemActionView; 1.15 +import org.mozilla.gecko.util.ThreadUtils; 1.16 + 1.17 +import android.content.Context; 1.18 +import android.content.Intent; 1.19 +import android.content.pm.PackageManager; 1.20 +import android.content.pm.ResolveInfo; 1.21 +import android.graphics.drawable.Drawable; 1.22 +import android.view.MenuItem; 1.23 +import android.view.MenuItem.OnMenuItemClickListener; 1.24 +import android.view.SubMenu; 1.25 +import android.view.View; 1.26 +import android.view.View.OnClickListener; 1.27 +import android.text.TextUtils; 1.28 + 1.29 +import java.util.ArrayList; 1.30 +import java.util.HashMap; 1.31 + 1.32 +public class GeckoActionProvider { 1.33 + private static int MAX_HISTORY_SIZE = 2; 1.34 + 1.35 + /** 1.36 + * A listener to know when a target was selected. 1.37 + * When setting a provider, the activity can listen to this, 1.38 + * to close the menu. 1.39 + */ 1.40 + public interface OnTargetSelectedListener { 1.41 + public void onTargetSelected(); 1.42 + } 1.43 + 1.44 + private final Context mContext; 1.45 + 1.46 + public final static String DEFAULT_MIME_TYPE = "text/plain"; 1.47 + 1.48 + public static final String DEFAULT_HISTORY_FILE_NAME = "history.xml"; 1.49 + 1.50 + // History file. 1.51 + private String mHistoryFileName = DEFAULT_HISTORY_FILE_NAME; 1.52 + 1.53 + private OnTargetSelectedListener mOnTargetListener; 1.54 + 1.55 + private final Callbacks mCallbacks = new Callbacks(); 1.56 + 1.57 + private static HashMap<String, GeckoActionProvider> mProviders = new HashMap<String, GeckoActionProvider>(); 1.58 + 1.59 + private static String getFilenameFromMimeType(String mimeType) { 1.60 + String[] mime = mimeType.split("/"); 1.61 + 1.62 + // All text mimetypes use the default provider 1.63 + if ("text".equals(mime[0])) { 1.64 + return DEFAULT_HISTORY_FILE_NAME; 1.65 + } 1.66 + 1.67 + return "history-" + mime[0] + ".xml"; 1.68 + } 1.69 + 1.70 + // Gets the action provider for a particular mimetype 1.71 + public static GeckoActionProvider getForType(String mimeType, Context context) { 1.72 + if (!mProviders.keySet().contains(mimeType)) { 1.73 + GeckoActionProvider provider = new GeckoActionProvider(context); 1.74 + 1.75 + // For empty types, we just return a default provider 1.76 + if (TextUtils.isEmpty(mimeType)) { 1.77 + return provider; 1.78 + } 1.79 + 1.80 + provider.setHistoryFileName(getFilenameFromMimeType(mimeType)); 1.81 + mProviders.put(mimeType, provider); 1.82 + } 1.83 + return mProviders.get(mimeType); 1.84 + } 1.85 + 1.86 + public GeckoActionProvider(Context context) { 1.87 + mContext = context; 1.88 + } 1.89 + 1.90 + public View onCreateActionView() { 1.91 + // Create the view and set its data model. 1.92 + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); 1.93 + MenuItemActionView view = new MenuItemActionView(mContext, null); 1.94 + view.addActionButtonClickListener(mCallbacks); 1.95 + 1.96 + final PackageManager packageManager = mContext.getPackageManager(); 1.97 + int historySize = dataModel.getDistinctActivityCountInHistory(); 1.98 + if (historySize > MAX_HISTORY_SIZE) { 1.99 + historySize = MAX_HISTORY_SIZE; 1.100 + } 1.101 + 1.102 + // Historical data is dependent on past selection of activities. 1.103 + // Activity count is determined by the number of activities that can handle 1.104 + // the particular intent. When no intent is set, the activity count is 0, 1.105 + // while the history count can be a valid number. 1.106 + if (historySize > dataModel.getActivityCount()) { 1.107 + return view; 1.108 + } 1.109 + 1.110 + for (int i = 0; i < historySize; i++) { 1.111 + view.addActionButton(dataModel.getActivity(i).loadIcon(packageManager)); 1.112 + } 1.113 + 1.114 + return view; 1.115 + } 1.116 + 1.117 + public View getView() { 1.118 + return onCreateActionView(); 1.119 + } 1.120 + 1.121 + public boolean hasSubMenu() { 1.122 + return true; 1.123 + } 1.124 + 1.125 + public void onPrepareSubMenu(SubMenu subMenu) { 1.126 + // Clear since the order of items may change. 1.127 + subMenu.clear(); 1.128 + 1.129 + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); 1.130 + PackageManager packageManager = mContext.getPackageManager(); 1.131 + 1.132 + // Populate the sub-menu with a sub set of the activities. 1.133 + final int count = dataModel.getActivityCount(); 1.134 + for (int i = 0; i < count; i++) { 1.135 + ResolveInfo activity = dataModel.getActivity(i); 1.136 + subMenu.add(0, i, i, activity.loadLabel(packageManager)) 1.137 + .setIcon(activity.loadIcon(packageManager)) 1.138 + .setOnMenuItemClickListener(mCallbacks); 1.139 + } 1.140 + } 1.141 + 1.142 + public void setHistoryFileName(String historyFile) { 1.143 + mHistoryFileName = historyFile; 1.144 + } 1.145 + 1.146 + public Intent getIntent() { 1.147 + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); 1.148 + return dataModel.getIntent(); 1.149 + } 1.150 + 1.151 + public void setIntent(Intent intent) { 1.152 + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); 1.153 + dataModel.setIntent(intent); 1.154 + 1.155 + // Inform the target listener to refresh it's UI, if needed. 1.156 + if (mOnTargetListener != null) { 1.157 + mOnTargetListener.onTargetSelected(); 1.158 + } 1.159 + } 1.160 + 1.161 + public void setOnTargetSelectedListener(OnTargetSelectedListener listener) { 1.162 + mOnTargetListener = listener; 1.163 + } 1.164 + 1.165 + public ArrayList<ResolveInfo> getSortedActivites() { 1.166 + ArrayList<ResolveInfo> infos = new ArrayList<ResolveInfo>(); 1.167 + 1.168 + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); 1.169 + PackageManager packageManager = mContext.getPackageManager(); 1.170 + 1.171 + // Populate the sub-menu with a sub set of the activities. 1.172 + final int count = dataModel.getActivityCount(); 1.173 + for (int i = 0; i < count; i++) { 1.174 + infos.add(dataModel.getActivity(i)); 1.175 + } 1.176 + return infos; 1.177 + } 1.178 + 1.179 + public void chooseActivity(int position) { 1.180 + mCallbacks.chooseActivity(position); 1.181 + } 1.182 + 1.183 + /** 1.184 + * Listener for handling default activity / menu item clicks. 1.185 + */ 1.186 + private class Callbacks implements OnMenuItemClickListener, 1.187 + OnClickListener { 1.188 + private void chooseActivity(int index) { 1.189 + final ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); 1.190 + final Intent launchIntent = dataModel.chooseActivity(index); 1.191 + if (launchIntent != null) { 1.192 + // This may cause a download to happen. Make sure we're on the background thread. 1.193 + ThreadUtils.postToBackgroundThread(new Runnable() { 1.194 + @Override 1.195 + public void run() { 1.196 + // Share image downloads the image before sharing it. 1.197 + String type = launchIntent.getType(); 1.198 + if (Intent.ACTION_SEND.equals(launchIntent.getAction()) && type != null && type.startsWith("image/")) { 1.199 + GeckoAppShell.downloadImageForIntent(launchIntent); 1.200 + } 1.201 + 1.202 + launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 1.203 + mContext.startActivity(launchIntent); 1.204 + } 1.205 + }); 1.206 + } 1.207 + 1.208 + if (mOnTargetListener != null) { 1.209 + mOnTargetListener.onTargetSelected(); 1.210 + } 1.211 + } 1.212 + 1.213 + @Override 1.214 + public boolean onMenuItemClick(MenuItem item) { 1.215 + chooseActivity(item.getItemId()); 1.216 + 1.217 + // Context: Sharing via chrome mainmenu list (no explicit session is active) 1.218 + Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST); 1.219 + return true; 1.220 + } 1.221 + 1.222 + @Override 1.223 + public void onClick(View view) { 1.224 + Integer index = (Integer) view.getTag(); 1.225 + chooseActivity(index); 1.226 + 1.227 + // Context: Sharing via chrome mainmenu and content contextmenu quickshare (no explicit session is active) 1.228 + Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.BUTTON); 1.229 + } 1.230 + } 1.231 +}