83e9f0ca9f3bad2bed02c41c166e7619516e0e68
[pub/Android/ownCloud.git] / actionbarsherlock / src / com / actionbarsherlock / widget / ShareActionProvider.java
1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.actionbarsherlock.widget;
18
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.pm.PackageManager;
22 import android.content.pm.ResolveInfo;
23 import android.graphics.drawable.Drawable;
24 import android.util.TypedValue;
25 import android.view.View;
26
27 import com.actionbarsherlock.R;
28 import com.actionbarsherlock.view.ActionProvider;
29 import com.actionbarsherlock.view.Menu;
30 import com.actionbarsherlock.view.MenuItem;
31 import com.actionbarsherlock.view.MenuItem.OnMenuItemClickListener;
32 import com.actionbarsherlock.view.SubMenu;
33 import com.actionbarsherlock.widget.ActivityChooserModel.OnChooseActivityListener;
34
35 /**
36 * This is a provider for a share action. It is responsible for creating views
37 * that enable data sharing and also to show a sub menu with sharing activities
38 * if the hosting item is placed on the overflow menu.
39 * <p>
40 * Here is how to use the action provider with custom backing file in a {@link MenuItem}:
41 * </p>
42 * <p>
43 * <pre>
44 * <code>
45 * // In Activity#onCreateOptionsMenu
46 * public boolean onCreateOptionsMenu(Menu menu) {
47 * // Get the menu item.
48 * MenuItem menuItem = menu.findItem(R.id.my_menu_item);
49 * // Get the provider and hold onto it to set/change the share intent.
50 * mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
51 * // Set history different from the default before getting the action
52 * // view since a call to {@link MenuItem#getActionView() MenuItem.getActionView()} calls
53 * // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this
54 * // line if using the default share history file is desired.
55 * mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
56 * . . .
57 * }
58 *
59 * // Somewhere in the application.
60 * public void doShare(Intent shareIntent) {
61 * // When you want to share set the share intent.
62 * mShareActionProvider.setShareIntent(shareIntent);
63 * }
64 * </pre>
65 * </code>
66 * </p>
67 * <p>
68 * <strong>Note:</strong> While the sample snippet demonstrates how to use this provider
69 * in the context of a menu item, the use of the provider is not limited to menu items.
70 * </p>
71 *
72 * @see ActionProvider
73 */
74 public class ShareActionProvider extends ActionProvider {
75
76 /**
77 * Listener for the event of selecting a share target.
78 */
79 public interface OnShareTargetSelectedListener {
80
81 /**
82 * Called when a share target has been selected. The client can
83 * decide whether to handle the intent or rely on the default
84 * behavior which is launching it.
85 * <p>
86 * <strong>Note:</strong> Modifying the intent is not permitted and
87 * any changes to the latter will be ignored.
88 * </p>
89 *
90 * @param source The source of the notification.
91 * @param intent The intent for launching the chosen share target.
92 * @return Whether the client has handled the intent.
93 */
94 public boolean onShareTargetSelected(ShareActionProvider source, Intent intent);
95 }
96
97 /**
98 * The default for the maximal number of activities shown in the sub-menu.
99 */
100 private static final int DEFAULT_INITIAL_ACTIVITY_COUNT = 4;
101
102 /**
103 * The the maximum number activities shown in the sub-menu.
104 */
105 private int mMaxShownActivityCount = DEFAULT_INITIAL_ACTIVITY_COUNT;
106
107 /**
108 * Listener for handling menu item clicks.
109 */
110 private final ShareMenuItemOnMenuItemClickListener mOnMenuItemClickListener =
111 new ShareMenuItemOnMenuItemClickListener();
112
113 /**
114 * The default name for storing share history.
115 */
116 public static final String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
117
118 /**
119 * Context for accessing resources.
120 */
121 private final Context mContext;
122
123 /**
124 * The name of the file with share history data.
125 */
126 private String mShareHistoryFileName = DEFAULT_SHARE_HISTORY_FILE_NAME;
127
128 private OnShareTargetSelectedListener mOnShareTargetSelectedListener;
129
130 private OnChooseActivityListener mOnChooseActivityListener;
131
132 /**
133 * Creates a new instance.
134 *
135 * @param context Context for accessing resources.
136 */
137 public ShareActionProvider(Context context) {
138 super(context);
139 mContext = context;
140 }
141
142 /**
143 * Sets a listener to be notified when a share target has been selected.
144 * The listener can optionally decide to handle the selection and
145 * not rely on the default behavior which is to launch the activity.
146 * <p>
147 * <strong>Note:</strong> If you choose the backing share history file
148 * you will still be notified in this callback.
149 * </p>
150 * @param listener The listener.
151 */
152 public void setOnShareTargetSelectedListener(OnShareTargetSelectedListener listener) {
153 mOnShareTargetSelectedListener = listener;
154 setActivityChooserPolicyIfNeeded();
155 }
156
157 /**
158 * {@inheritDoc}
159 */
160 @Override
161 public View onCreateActionView() {
162 // Create the view and set its data model.
163 ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
164 ActivityChooserView activityChooserView = new ActivityChooserView(mContext);
165 activityChooserView.setActivityChooserModel(dataModel);
166
167 // Lookup and set the expand action icon.
168 TypedValue outTypedValue = new TypedValue();
169 mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true);
170 Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId);
171 activityChooserView.setExpandActivityOverflowButtonDrawable(drawable);
172 activityChooserView.setProvider(this);
173
174 // Set content description.
175 activityChooserView.setDefaultActionButtonContentDescription(
176 R.string.abs__shareactionprovider_share_with_application);
177 activityChooserView.setExpandActivityOverflowButtonContentDescription(
178 R.string.abs__shareactionprovider_share_with);
179
180 return activityChooserView;
181 }
182
183 /**
184 * {@inheritDoc}
185 */
186 @Override
187 public boolean hasSubMenu() {
188 return true;
189 }
190
191 /**
192 * {@inheritDoc}
193 */
194 @Override
195 public void onPrepareSubMenu(SubMenu subMenu) {
196 // Clear since the order of items may change.
197 subMenu.clear();
198
199 ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
200 PackageManager packageManager = mContext.getPackageManager();
201
202 final int expandedActivityCount = dataModel.getActivityCount();
203 final int collapsedActivityCount = Math.min(expandedActivityCount, mMaxShownActivityCount);
204
205 // Populate the sub-menu with a sub set of the activities.
206 for (int i = 0; i < collapsedActivityCount; i++) {
207 ResolveInfo activity = dataModel.getActivity(i);
208 subMenu.add(0, i, i, activity.loadLabel(packageManager))
209 .setIcon(activity.loadIcon(packageManager))
210 .setOnMenuItemClickListener(mOnMenuItemClickListener);
211 }
212
213 if (collapsedActivityCount < expandedActivityCount) {
214 // Add a sub-menu for showing all activities as a list item.
215 SubMenu expandedSubMenu = subMenu.addSubMenu(Menu.NONE, collapsedActivityCount,
216 collapsedActivityCount,
217 mContext.getString(R.string.abs__activity_chooser_view_see_all));
218 for (int i = 0; i < expandedActivityCount; i++) {
219 ResolveInfo activity = dataModel.getActivity(i);
220 expandedSubMenu.add(0, i, i, activity.loadLabel(packageManager))
221 .setIcon(activity.loadIcon(packageManager))
222 .setOnMenuItemClickListener(mOnMenuItemClickListener);
223 }
224 }
225 }
226
227 /**
228 * Sets the file name of a file for persisting the share history which
229 * history will be used for ordering share targets. This file will be used
230 * for all view created by {@link #onCreateActionView()}. Defaults to
231 * {@link #DEFAULT_SHARE_HISTORY_FILE_NAME}. Set to <code>null</code>
232 * if share history should not be persisted between sessions.
233 * <p>
234 * <strong>Note:</strong> The history file name can be set any time, however
235 * only the action views created by {@link #onCreateActionView()} after setting
236 * the file name will be backed by the provided file.
237 * <p>
238 *
239 * @param shareHistoryFile The share history file name.
240 */
241 public void setShareHistoryFileName(String shareHistoryFile) {
242 mShareHistoryFileName = shareHistoryFile;
243 setActivityChooserPolicyIfNeeded();
244 }
245
246 /**
247 * Sets an intent with information about the share action. Here is a
248 * sample for constructing a share intent:
249 * <p>
250 * <pre>
251 * <code>
252 * Intent shareIntent = new Intent(Intent.ACTION_SEND);
253 * shareIntent.setType("image/*");
254 * Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg"));
255 * shareIntent.putExtra(Intent.EXTRA_STREAM, uri.toString());
256 * </pre>
257 * </code>
258 * </p>
259 *
260 * @param shareIntent The share intent.
261 *
262 * @see Intent#ACTION_SEND
263 * @see Intent#ACTION_SEND_MULTIPLE
264 */
265 public void setShareIntent(Intent shareIntent) {
266 ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
267 mShareHistoryFileName);
268 dataModel.setIntent(shareIntent);
269 }
270
271 /**
272 * Reusable listener for handling share item clicks.
273 */
274 private class ShareMenuItemOnMenuItemClickListener implements OnMenuItemClickListener {
275 @Override
276 public boolean onMenuItemClick(MenuItem item) {
277 ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
278 mShareHistoryFileName);
279 final int itemId = item.getItemId();
280 Intent launchIntent = dataModel.chooseActivity(itemId);
281 if (launchIntent != null) {
282 mContext.startActivity(launchIntent);
283 }
284 return true;
285 }
286 }
287
288 /**
289 * Set the activity chooser policy of the model backed by the current
290 * share history file if needed which is if there is a registered callback.
291 */
292 private void setActivityChooserPolicyIfNeeded() {
293 if (mOnShareTargetSelectedListener == null) {
294 return;
295 }
296 if (mOnChooseActivityListener == null) {
297 mOnChooseActivityListener = new ShareAcitivityChooserModelPolicy();
298 }
299 ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
300 dataModel.setOnChooseActivityListener(mOnChooseActivityListener);
301 }
302
303 /**
304 * Policy that delegates to the {@link OnShareTargetSelectedListener}, if such.
305 */
306 private class ShareAcitivityChooserModelPolicy implements OnChooseActivityListener {
307 @Override
308 public boolean onChooseActivity(ActivityChooserModel host, Intent intent) {
309 if (mOnShareTargetSelectedListener != null) {
310 return mOnShareTargetSelectedListener.onShareTargetSelected(
311 ShareActionProvider.this, intent);
312 }
313 return false;
314 }
315 }
316 }