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