Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- |
michael@0 | 2 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | package org.mozilla.gecko.widget; |
michael@0 | 7 | |
michael@0 | 8 | import org.mozilla.gecko.GeckoAppShell; |
michael@0 | 9 | import org.mozilla.gecko.Telemetry; |
michael@0 | 10 | import org.mozilla.gecko.TelemetryContract; |
michael@0 | 11 | import org.mozilla.gecko.menu.MenuItemActionView; |
michael@0 | 12 | import org.mozilla.gecko.util.ThreadUtils; |
michael@0 | 13 | |
michael@0 | 14 | import android.content.Context; |
michael@0 | 15 | import android.content.Intent; |
michael@0 | 16 | import android.content.pm.PackageManager; |
michael@0 | 17 | import android.content.pm.ResolveInfo; |
michael@0 | 18 | import android.graphics.drawable.Drawable; |
michael@0 | 19 | import android.view.MenuItem; |
michael@0 | 20 | import android.view.MenuItem.OnMenuItemClickListener; |
michael@0 | 21 | import android.view.SubMenu; |
michael@0 | 22 | import android.view.View; |
michael@0 | 23 | import android.view.View.OnClickListener; |
michael@0 | 24 | import android.text.TextUtils; |
michael@0 | 25 | |
michael@0 | 26 | import java.util.ArrayList; |
michael@0 | 27 | import java.util.HashMap; |
michael@0 | 28 | |
michael@0 | 29 | public class GeckoActionProvider { |
michael@0 | 30 | private static int MAX_HISTORY_SIZE = 2; |
michael@0 | 31 | |
michael@0 | 32 | /** |
michael@0 | 33 | * A listener to know when a target was selected. |
michael@0 | 34 | * When setting a provider, the activity can listen to this, |
michael@0 | 35 | * to close the menu. |
michael@0 | 36 | */ |
michael@0 | 37 | public interface OnTargetSelectedListener { |
michael@0 | 38 | public void onTargetSelected(); |
michael@0 | 39 | } |
michael@0 | 40 | |
michael@0 | 41 | private final Context mContext; |
michael@0 | 42 | |
michael@0 | 43 | public final static String DEFAULT_MIME_TYPE = "text/plain"; |
michael@0 | 44 | |
michael@0 | 45 | public static final String DEFAULT_HISTORY_FILE_NAME = "history.xml"; |
michael@0 | 46 | |
michael@0 | 47 | // History file. |
michael@0 | 48 | private String mHistoryFileName = DEFAULT_HISTORY_FILE_NAME; |
michael@0 | 49 | |
michael@0 | 50 | private OnTargetSelectedListener mOnTargetListener; |
michael@0 | 51 | |
michael@0 | 52 | private final Callbacks mCallbacks = new Callbacks(); |
michael@0 | 53 | |
michael@0 | 54 | private static HashMap<String, GeckoActionProvider> mProviders = new HashMap<String, GeckoActionProvider>(); |
michael@0 | 55 | |
michael@0 | 56 | private static String getFilenameFromMimeType(String mimeType) { |
michael@0 | 57 | String[] mime = mimeType.split("/"); |
michael@0 | 58 | |
michael@0 | 59 | // All text mimetypes use the default provider |
michael@0 | 60 | if ("text".equals(mime[0])) { |
michael@0 | 61 | return DEFAULT_HISTORY_FILE_NAME; |
michael@0 | 62 | } |
michael@0 | 63 | |
michael@0 | 64 | return "history-" + mime[0] + ".xml"; |
michael@0 | 65 | } |
michael@0 | 66 | |
michael@0 | 67 | // Gets the action provider for a particular mimetype |
michael@0 | 68 | public static GeckoActionProvider getForType(String mimeType, Context context) { |
michael@0 | 69 | if (!mProviders.keySet().contains(mimeType)) { |
michael@0 | 70 | GeckoActionProvider provider = new GeckoActionProvider(context); |
michael@0 | 71 | |
michael@0 | 72 | // For empty types, we just return a default provider |
michael@0 | 73 | if (TextUtils.isEmpty(mimeType)) { |
michael@0 | 74 | return provider; |
michael@0 | 75 | } |
michael@0 | 76 | |
michael@0 | 77 | provider.setHistoryFileName(getFilenameFromMimeType(mimeType)); |
michael@0 | 78 | mProviders.put(mimeType, provider); |
michael@0 | 79 | } |
michael@0 | 80 | return mProviders.get(mimeType); |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | public GeckoActionProvider(Context context) { |
michael@0 | 84 | mContext = context; |
michael@0 | 85 | } |
michael@0 | 86 | |
michael@0 | 87 | public View onCreateActionView() { |
michael@0 | 88 | // Create the view and set its data model. |
michael@0 | 89 | ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); |
michael@0 | 90 | MenuItemActionView view = new MenuItemActionView(mContext, null); |
michael@0 | 91 | view.addActionButtonClickListener(mCallbacks); |
michael@0 | 92 | |
michael@0 | 93 | final PackageManager packageManager = mContext.getPackageManager(); |
michael@0 | 94 | int historySize = dataModel.getDistinctActivityCountInHistory(); |
michael@0 | 95 | if (historySize > MAX_HISTORY_SIZE) { |
michael@0 | 96 | historySize = MAX_HISTORY_SIZE; |
michael@0 | 97 | } |
michael@0 | 98 | |
michael@0 | 99 | // Historical data is dependent on past selection of activities. |
michael@0 | 100 | // Activity count is determined by the number of activities that can handle |
michael@0 | 101 | // the particular intent. When no intent is set, the activity count is 0, |
michael@0 | 102 | // while the history count can be a valid number. |
michael@0 | 103 | if (historySize > dataModel.getActivityCount()) { |
michael@0 | 104 | return view; |
michael@0 | 105 | } |
michael@0 | 106 | |
michael@0 | 107 | for (int i = 0; i < historySize; i++) { |
michael@0 | 108 | view.addActionButton(dataModel.getActivity(i).loadIcon(packageManager)); |
michael@0 | 109 | } |
michael@0 | 110 | |
michael@0 | 111 | return view; |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | public View getView() { |
michael@0 | 115 | return onCreateActionView(); |
michael@0 | 116 | } |
michael@0 | 117 | |
michael@0 | 118 | public boolean hasSubMenu() { |
michael@0 | 119 | return true; |
michael@0 | 120 | } |
michael@0 | 121 | |
michael@0 | 122 | public void onPrepareSubMenu(SubMenu subMenu) { |
michael@0 | 123 | // Clear since the order of items may change. |
michael@0 | 124 | subMenu.clear(); |
michael@0 | 125 | |
michael@0 | 126 | ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); |
michael@0 | 127 | PackageManager packageManager = mContext.getPackageManager(); |
michael@0 | 128 | |
michael@0 | 129 | // Populate the sub-menu with a sub set of the activities. |
michael@0 | 130 | final int count = dataModel.getActivityCount(); |
michael@0 | 131 | for (int i = 0; i < count; i++) { |
michael@0 | 132 | ResolveInfo activity = dataModel.getActivity(i); |
michael@0 | 133 | subMenu.add(0, i, i, activity.loadLabel(packageManager)) |
michael@0 | 134 | .setIcon(activity.loadIcon(packageManager)) |
michael@0 | 135 | .setOnMenuItemClickListener(mCallbacks); |
michael@0 | 136 | } |
michael@0 | 137 | } |
michael@0 | 138 | |
michael@0 | 139 | public void setHistoryFileName(String historyFile) { |
michael@0 | 140 | mHistoryFileName = historyFile; |
michael@0 | 141 | } |
michael@0 | 142 | |
michael@0 | 143 | public Intent getIntent() { |
michael@0 | 144 | ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); |
michael@0 | 145 | return dataModel.getIntent(); |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | public void setIntent(Intent intent) { |
michael@0 | 149 | ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); |
michael@0 | 150 | dataModel.setIntent(intent); |
michael@0 | 151 | |
michael@0 | 152 | // Inform the target listener to refresh it's UI, if needed. |
michael@0 | 153 | if (mOnTargetListener != null) { |
michael@0 | 154 | mOnTargetListener.onTargetSelected(); |
michael@0 | 155 | } |
michael@0 | 156 | } |
michael@0 | 157 | |
michael@0 | 158 | public void setOnTargetSelectedListener(OnTargetSelectedListener listener) { |
michael@0 | 159 | mOnTargetListener = listener; |
michael@0 | 160 | } |
michael@0 | 161 | |
michael@0 | 162 | public ArrayList<ResolveInfo> getSortedActivites() { |
michael@0 | 163 | ArrayList<ResolveInfo> infos = new ArrayList<ResolveInfo>(); |
michael@0 | 164 | |
michael@0 | 165 | ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); |
michael@0 | 166 | PackageManager packageManager = mContext.getPackageManager(); |
michael@0 | 167 | |
michael@0 | 168 | // Populate the sub-menu with a sub set of the activities. |
michael@0 | 169 | final int count = dataModel.getActivityCount(); |
michael@0 | 170 | for (int i = 0; i < count; i++) { |
michael@0 | 171 | infos.add(dataModel.getActivity(i)); |
michael@0 | 172 | } |
michael@0 | 173 | return infos; |
michael@0 | 174 | } |
michael@0 | 175 | |
michael@0 | 176 | public void chooseActivity(int position) { |
michael@0 | 177 | mCallbacks.chooseActivity(position); |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | /** |
michael@0 | 181 | * Listener for handling default activity / menu item clicks. |
michael@0 | 182 | */ |
michael@0 | 183 | private class Callbacks implements OnMenuItemClickListener, |
michael@0 | 184 | OnClickListener { |
michael@0 | 185 | private void chooseActivity(int index) { |
michael@0 | 186 | final ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mHistoryFileName); |
michael@0 | 187 | final Intent launchIntent = dataModel.chooseActivity(index); |
michael@0 | 188 | if (launchIntent != null) { |
michael@0 | 189 | // This may cause a download to happen. Make sure we're on the background thread. |
michael@0 | 190 | ThreadUtils.postToBackgroundThread(new Runnable() { |
michael@0 | 191 | @Override |
michael@0 | 192 | public void run() { |
michael@0 | 193 | // Share image downloads the image before sharing it. |
michael@0 | 194 | String type = launchIntent.getType(); |
michael@0 | 195 | if (Intent.ACTION_SEND.equals(launchIntent.getAction()) && type != null && type.startsWith("image/")) { |
michael@0 | 196 | GeckoAppShell.downloadImageForIntent(launchIntent); |
michael@0 | 197 | } |
michael@0 | 198 | |
michael@0 | 199 | launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); |
michael@0 | 200 | mContext.startActivity(launchIntent); |
michael@0 | 201 | } |
michael@0 | 202 | }); |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | if (mOnTargetListener != null) { |
michael@0 | 206 | mOnTargetListener.onTargetSelected(); |
michael@0 | 207 | } |
michael@0 | 208 | } |
michael@0 | 209 | |
michael@0 | 210 | @Override |
michael@0 | 211 | public boolean onMenuItemClick(MenuItem item) { |
michael@0 | 212 | chooseActivity(item.getItemId()); |
michael@0 | 213 | |
michael@0 | 214 | // Context: Sharing via chrome mainmenu list (no explicit session is active) |
michael@0 | 215 | Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST); |
michael@0 | 216 | return true; |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | @Override |
michael@0 | 220 | public void onClick(View view) { |
michael@0 | 221 | Integer index = (Integer) view.getTag(); |
michael@0 | 222 | chooseActivity(index); |
michael@0 | 223 | |
michael@0 | 224 | // Context: Sharing via chrome mainmenu and content contextmenu quickshare (no explicit session is active) |
michael@0 | 225 | Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.BUTTON); |
michael@0 | 226 | } |
michael@0 | 227 | } |
michael@0 | 228 | } |