create changelog entry
[debian/openrocket] / android-libraries / 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 }