e19ea9e9e1c99db0eb9778b7b9c3d5d3db47b602
[pub/Android/ownCloud.git] / actionbarsherlock / src / com / actionbarsherlock / widget / ActivityChooserView.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.os.Build;
20 import com.actionbarsherlock.R;
21 import com.actionbarsherlock.internal.widget.IcsLinearLayout;
22 import com.actionbarsherlock.internal.widget.IcsListPopupWindow;
23 import com.actionbarsherlock.view.ActionProvider;
24 import com.actionbarsherlock.widget.ActivityChooserModel.ActivityChooserModelClient;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.pm.PackageManager;
28 import android.content.pm.ResolveInfo;
29 import android.content.res.Resources;
30 import android.content.res.TypedArray;
31 import android.database.DataSetObserver;
32 import android.graphics.drawable.Drawable;
33 import android.util.AttributeSet;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.ViewGroup;
37 import android.view.ViewTreeObserver;
38 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
39 import android.widget.AdapterView;
40 import android.widget.BaseAdapter;
41 import android.widget.FrameLayout;
42 import android.widget.ImageView;
43 import android.widget.PopupWindow;
44 import android.widget.TextView;
45
46 /**
47 * This class is a view for choosing an activity for handling a given {@link Intent}.
48 * <p>
49 * The view is composed of two adjacent buttons:
50 * <ul>
51 * <li>
52 * The left button is an immediate action and allows one click activity choosing.
53 * Tapping this button immediately executes the intent without requiring any further
54 * user input. Long press on this button shows a popup for changing the default
55 * activity.
56 * </li>
57 * <li>
58 * The right button is an overflow action and provides an optimized menu
59 * of additional activities. Tapping this button shows a popup anchored to this
60 * view, listing the most frequently used activities. This list is initially
61 * limited to a small number of items in frequency used order. The last item,
62 * "Show all..." serves as an affordance to display all available activities.
63 * </li>
64 * </ul>
65 * </p>
66 *
67 * @hide
68 */
69 class ActivityChooserView extends ViewGroup implements ActivityChooserModelClient {
70
71 /**
72 * An adapter for displaying the activities in an {@link AdapterView}.
73 */
74 private final ActivityChooserViewAdapter mAdapter;
75
76 /**
77 * Implementation of various interfaces to avoid publishing them in the APIs.
78 */
79 private final Callbacks mCallbacks;
80
81 /**
82 * The content of this view.
83 */
84 private final IcsLinearLayout mActivityChooserContent;
85
86 /**
87 * Stores the background drawable to allow hiding and latter showing.
88 */
89 private final Drawable mActivityChooserContentBackground;
90
91 /**
92 * The expand activities action button;
93 */
94 private final FrameLayout mExpandActivityOverflowButton;
95
96 /**
97 * The image for the expand activities action button;
98 */
99 private final ImageView mExpandActivityOverflowButtonImage;
100
101 /**
102 * The default activities action button;
103 */
104 private final FrameLayout mDefaultActivityButton;
105
106 /**
107 * The image for the default activities action button;
108 */
109 private final ImageView mDefaultActivityButtonImage;
110
111 /**
112 * The maximal width of the list popup.
113 */
114 private final int mListPopupMaxWidth;
115
116 /**
117 * The ActionProvider hosting this view, if applicable.
118 */
119 ActionProvider mProvider;
120
121 /**
122 * Observer for the model data.
123 */
124 private final DataSetObserver mModelDataSetOberver = new DataSetObserver() {
125
126 @Override
127 public void onChanged() {
128 super.onChanged();
129 mAdapter.notifyDataSetChanged();
130 }
131 @Override
132 public void onInvalidated() {
133 super.onInvalidated();
134 mAdapter.notifyDataSetInvalidated();
135 }
136 };
137
138 private final OnGlobalLayoutListener mOnGlobalLayoutListener = new OnGlobalLayoutListener() {
139 @Override
140 public void onGlobalLayout() {
141 if (isShowingPopup()) {
142 if (!isShown()) {
143 getListPopupWindow().dismiss();
144 } else {
145 getListPopupWindow().show();
146 if (mProvider != null) {
147 mProvider.subUiVisibilityChanged(true);
148 }
149 }
150 }
151 }
152 };
153
154 /**
155 * Popup window for showing the activity overflow list.
156 */
157 private IcsListPopupWindow mListPopupWindow;
158
159 /**
160 * Listener for the dismissal of the popup/alert.
161 */
162 private PopupWindow.OnDismissListener mOnDismissListener;
163
164 /**
165 * Flag whether a default activity currently being selected.
166 */
167 private boolean mIsSelectingDefaultActivity;
168
169 /**
170 * The count of activities in the popup.
171 */
172 private int mInitialActivityCount = ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_DEFAULT;
173
174 /**
175 * Flag whether this view is attached to a window.
176 */
177 private boolean mIsAttachedToWindow;
178
179 /**
180 * String resource for formatting content description of the default target.
181 */
182 private int mDefaultActionButtonContentDescription;
183
184 private final Context mContext;
185
186 /**
187 * Create a new instance.
188 *
189 * @param context The application environment.
190 */
191 public ActivityChooserView(Context context) {
192 this(context, null);
193 }
194
195 /**
196 * Create a new instance.
197 *
198 * @param context The application environment.
199 * @param attrs A collection of attributes.
200 */
201 public ActivityChooserView(Context context, AttributeSet attrs) {
202 this(context, attrs, 0);
203 }
204
205 /**
206 * Create a new instance.
207 *
208 * @param context The application environment.
209 * @param attrs A collection of attributes.
210 * @param defStyle The default style to apply to this view.
211 */
212 public ActivityChooserView(Context context, AttributeSet attrs, int defStyle) {
213 super(context, attrs, defStyle);
214 mContext = context;
215
216 TypedArray attributesArray = context.obtainStyledAttributes(attrs,
217 R.styleable.SherlockActivityChooserView, defStyle, 0);
218
219 mInitialActivityCount = attributesArray.getInt(
220 R.styleable.SherlockActivityChooserView_initialActivityCount,
221 ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_DEFAULT);
222
223 Drawable expandActivityOverflowButtonDrawable = attributesArray.getDrawable(
224 R.styleable.SherlockActivityChooserView_expandActivityOverflowButtonDrawable);
225
226 attributesArray.recycle();
227
228 LayoutInflater inflater = LayoutInflater.from(mContext);
229 inflater.inflate(R.layout.abs__activity_chooser_view, this, true);
230
231 mCallbacks = new Callbacks();
232
233 mActivityChooserContent = (IcsLinearLayout) findViewById(R.id.abs__activity_chooser_view_content);
234 mActivityChooserContentBackground = mActivityChooserContent.getBackground();
235
236 mDefaultActivityButton = (FrameLayout) findViewById(R.id.abs__default_activity_button);
237 mDefaultActivityButton.setOnClickListener(mCallbacks);
238 mDefaultActivityButton.setOnLongClickListener(mCallbacks);
239 mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.abs__image);
240
241 mExpandActivityOverflowButton = (FrameLayout) findViewById(R.id.abs__expand_activities_button);
242 mExpandActivityOverflowButton.setOnClickListener(mCallbacks);
243 mExpandActivityOverflowButtonImage =
244 (ImageView) mExpandActivityOverflowButton.findViewById(R.id.abs__image);
245 mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable);
246
247 mAdapter = new ActivityChooserViewAdapter();
248 mAdapter.registerDataSetObserver(new DataSetObserver() {
249 @Override
250 public void onChanged() {
251 super.onChanged();
252 updateAppearance();
253 }
254 });
255
256 Resources resources = context.getResources();
257 mListPopupMaxWidth = Math.max(resources.getDisplayMetrics().widthPixels / 2,
258 resources.getDimensionPixelSize(R.dimen.abs__config_prefDialogWidth));
259 }
260
261 /**
262 * {@inheritDoc}
263 */
264 public void setActivityChooserModel(ActivityChooserModel dataModel) {
265 mAdapter.setDataModel(dataModel);
266 if (isShowingPopup()) {
267 dismissPopup();
268 showPopup();
269 }
270 }
271
272 /**
273 * Sets the background for the button that expands the activity
274 * overflow list.
275 *
276 * <strong>Note:</strong> Clients would like to set this drawable
277 * as a clue about the action the chosen activity will perform. For
278 * example, if a share activity is to be chosen the drawable should
279 * give a clue that sharing is to be performed.
280 *
281 * @param drawable The drawable.
282 */
283 public void setExpandActivityOverflowButtonDrawable(Drawable drawable) {
284 mExpandActivityOverflowButtonImage.setImageDrawable(drawable);
285 }
286
287 /**
288 * Sets the content description for the button that expands the activity
289 * overflow list.
290 *
291 * description as a clue about the action performed by the button.
292 * For example, if a share activity is to be chosen the content
293 * description should be something like "Share with".
294 *
295 * @param resourceId The content description resource id.
296 */
297 public void setExpandActivityOverflowButtonContentDescription(int resourceId) {
298 CharSequence contentDescription = mContext.getString(resourceId);
299 mExpandActivityOverflowButtonImage.setContentDescription(contentDescription);
300 }
301
302 /**
303 * Set the provider hosting this view, if applicable.
304 * @hide Internal use only
305 */
306 public void setProvider(ActionProvider provider) {
307 mProvider = provider;
308 }
309
310 /**
311 * Shows the popup window with activities.
312 *
313 * @return True if the popup was shown, false if already showing.
314 */
315 public boolean showPopup() {
316 if (isShowingPopup() || !mIsAttachedToWindow) {
317 return false;
318 }
319 mIsSelectingDefaultActivity = false;
320 showPopupUnchecked(mInitialActivityCount);
321 return true;
322 }
323
324 /**
325 * Shows the popup no matter if it was already showing.
326 *
327 * @param maxActivityCount The max number of activities to display.
328 */
329 private void showPopupUnchecked(int maxActivityCount) {
330 if (mAdapter.getDataModel() == null) {
331 throw new IllegalStateException("No data model. Did you call #setDataModel?");
332 }
333
334 getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
335
336 final boolean defaultActivityButtonShown =
337 mDefaultActivityButton.getVisibility() == VISIBLE;
338
339 final int activityCount = mAdapter.getActivityCount();
340 final int maxActivityCountOffset = defaultActivityButtonShown ? 1 : 0;
341 if (maxActivityCount != ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED
342 && activityCount > maxActivityCount + maxActivityCountOffset) {
343 mAdapter.setShowFooterView(true);
344 mAdapter.setMaxActivityCount(maxActivityCount - 1);
345 } else {
346 mAdapter.setShowFooterView(false);
347 mAdapter.setMaxActivityCount(maxActivityCount);
348 }
349
350 IcsListPopupWindow popupWindow = getListPopupWindow();
351 if (!popupWindow.isShowing()) {
352 if (mIsSelectingDefaultActivity || !defaultActivityButtonShown) {
353 mAdapter.setShowDefaultActivity(true, defaultActivityButtonShown);
354 } else {
355 mAdapter.setShowDefaultActivity(false, false);
356 }
357 final int contentWidth = Math.min(mAdapter.measureContentWidth(), mListPopupMaxWidth);
358 popupWindow.setContentWidth(contentWidth);
359 popupWindow.show();
360 if (mProvider != null) {
361 mProvider.subUiVisibilityChanged(true);
362 }
363 popupWindow.getListView().setContentDescription(mContext.getString(
364 R.string.abs__activitychooserview_choose_application));
365 }
366 }
367
368 /**
369 * Dismisses the popup window with activities.
370 *
371 * @return True if dismissed, false if already dismissed.
372 */
373 public boolean dismissPopup() {
374 if (isShowingPopup()) {
375 getListPopupWindow().dismiss();
376 ViewTreeObserver viewTreeObserver = getViewTreeObserver();
377 if (viewTreeObserver.isAlive()) {
378 viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
379 }
380 }
381 return true;
382 }
383
384 /**
385 * Gets whether the popup window with activities is shown.
386 *
387 * @return True if the popup is shown.
388 */
389 public boolean isShowingPopup() {
390 return getListPopupWindow().isShowing();
391 }
392
393 @Override
394 protected void onAttachedToWindow() {
395 super.onAttachedToWindow();
396 ActivityChooserModel dataModel = mAdapter.getDataModel();
397 if (dataModel != null) {
398 dataModel.registerObserver(mModelDataSetOberver);
399 }
400 mIsAttachedToWindow = true;
401 }
402
403 @Override
404 protected void onDetachedFromWindow() {
405 super.onDetachedFromWindow();
406 ActivityChooserModel dataModel = mAdapter.getDataModel();
407 if (dataModel != null) {
408 try {
409 dataModel.unregisterObserver(mModelDataSetOberver);
410 } catch (IllegalStateException e) {
411 //Oh, well... fixes issue #557
412 }
413 }
414 ViewTreeObserver viewTreeObserver = getViewTreeObserver();
415 if (viewTreeObserver.isAlive()) {
416 viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
417 }
418 mIsAttachedToWindow = false;
419 }
420
421 @Override
422 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
423 View child = mActivityChooserContent;
424 // If the default action is not visible we want to be as tall as the
425 // ActionBar so if this widget is used in the latter it will look as
426 // a normal action button.
427 if (mDefaultActivityButton.getVisibility() != VISIBLE) {
428 heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
429 MeasureSpec.EXACTLY);
430 }
431 measureChild(child, widthMeasureSpec, heightMeasureSpec);
432 setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());
433 }
434
435 @Override
436 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
437 mActivityChooserContent.layout(0, 0, right - left, bottom - top);
438 if (getListPopupWindow().isShowing()) {
439 showPopupUnchecked(mAdapter.getMaxActivityCount());
440 } else {
441 dismissPopup();
442 }
443 }
444
445 public ActivityChooserModel getDataModel() {
446 return mAdapter.getDataModel();
447 }
448
449 /**
450 * Sets a listener to receive a callback when the popup is dismissed.
451 *
452 * @param listener The listener to be notified.
453 */
454 public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
455 mOnDismissListener = listener;
456 }
457
458 /**
459 * Sets the initial count of items shown in the activities popup
460 * i.e. the items before the popup is expanded. This is an upper
461 * bound since it is not guaranteed that such number of intent
462 * handlers exist.
463 *
464 * @param itemCount The initial popup item count.
465 */
466 public void setInitialActivityCount(int itemCount) {
467 mInitialActivityCount = itemCount;
468 }
469
470 /**
471 * Sets a content description of the default action button. This
472 * resource should be a string taking one formatting argument and
473 * will be used for formatting the content description of the button
474 * dynamically as the default target changes. For example, a resource
475 * pointing to the string "share with %1$s" will result in a content
476 * description "share with Bluetooth" for the Bluetooth activity.
477 *
478 * @param resourceId The resource id.
479 */
480 public void setDefaultActionButtonContentDescription(int resourceId) {
481 mDefaultActionButtonContentDescription = resourceId;
482 }
483
484 /**
485 * Gets the list popup window which is lazily initialized.
486 *
487 * @return The popup.
488 */
489 private IcsListPopupWindow getListPopupWindow() {
490 if (mListPopupWindow == null) {
491 mListPopupWindow = new IcsListPopupWindow(getContext());
492 mListPopupWindow.setAdapter(mAdapter);
493 mListPopupWindow.setAnchorView(ActivityChooserView.this);
494 mListPopupWindow.setModal(true);
495 mListPopupWindow.setOnItemClickListener(mCallbacks);
496 mListPopupWindow.setOnDismissListener(mCallbacks);
497 }
498 return mListPopupWindow;
499 }
500
501 /**
502 * Updates the buttons state.
503 */
504 private void updateAppearance() {
505 // Expand overflow button.
506 if (mAdapter.getCount() > 0) {
507 mExpandActivityOverflowButton.setEnabled(true);
508 } else {
509 mExpandActivityOverflowButton.setEnabled(false);
510 }
511 // Default activity button.
512 final int activityCount = mAdapter.getActivityCount();
513 final int historySize = mAdapter.getHistorySize();
514 if (activityCount > 0 && historySize > 0) {
515 mDefaultActivityButton.setVisibility(VISIBLE);
516 ResolveInfo activity = mAdapter.getDefaultActivity();
517 PackageManager packageManager = mContext.getPackageManager();
518 mDefaultActivityButtonImage.setImageDrawable(activity.loadIcon(packageManager));
519 if (mDefaultActionButtonContentDescription != 0) {
520 CharSequence label = activity.loadLabel(packageManager);
521 String contentDescription = mContext.getString(
522 mDefaultActionButtonContentDescription, label);
523 mDefaultActivityButton.setContentDescription(contentDescription);
524 }
525 } else {
526 mDefaultActivityButton.setVisibility(View.GONE);
527 }
528 // Activity chooser content.
529 if (mDefaultActivityButton.getVisibility() == VISIBLE) {
530 mActivityChooserContent.setBackgroundDrawable(mActivityChooserContentBackground);
531 } else {
532 mActivityChooserContent.setBackgroundDrawable(null);
533 mActivityChooserContent.setPadding(0, 0, 0, 0);
534 }
535 }
536
537 /**
538 * Interface implementation to avoid publishing them in the APIs.
539 */
540 private class Callbacks implements AdapterView.OnItemClickListener,
541 View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener {
542
543 // AdapterView#OnItemClickListener
544 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
545 ActivityChooserViewAdapter adapter = (ActivityChooserViewAdapter) parent.getAdapter();
546 final int itemViewType = adapter.getItemViewType(position);
547 switch (itemViewType) {
548 case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_FOOTER: {
549 showPopupUnchecked(ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED);
550 } break;
551 case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_ACTIVITY: {
552 dismissPopup();
553 if (mIsSelectingDefaultActivity) {
554 // The item at position zero is the default already.
555 if (position > 0) {
556 mAdapter.getDataModel().setDefaultActivity(position);
557 }
558 } else {
559 // If the default target is not shown in the list, the first
560 // item in the model is default action => adjust index
561 position = mAdapter.getShowDefaultActivity() ? position : position + 1;
562 Intent launchIntent = mAdapter.getDataModel().chooseActivity(position);
563 if (launchIntent != null) {
564 mContext.startActivity(launchIntent);
565 }
566 }
567 } break;
568 default:
569 throw new IllegalArgumentException();
570 }
571 }
572
573 // View.OnClickListener
574 public void onClick(View view) {
575 if (view == mDefaultActivityButton) {
576 dismissPopup();
577 ResolveInfo defaultActivity = mAdapter.getDefaultActivity();
578 final int index = mAdapter.getDataModel().getActivityIndex(defaultActivity);
579 Intent launchIntent = mAdapter.getDataModel().chooseActivity(index);
580 if (launchIntent != null) {
581 mContext.startActivity(launchIntent);
582 }
583 } else if (view == mExpandActivityOverflowButton) {
584 mIsSelectingDefaultActivity = false;
585 showPopupUnchecked(mInitialActivityCount);
586 } else {
587 throw new IllegalArgumentException();
588 }
589 }
590
591 // OnLongClickListener#onLongClick
592 @Override
593 public boolean onLongClick(View view) {
594 if (view == mDefaultActivityButton) {
595 if (mAdapter.getCount() > 0) {
596 mIsSelectingDefaultActivity = true;
597 showPopupUnchecked(mInitialActivityCount);
598 }
599 } else {
600 throw new IllegalArgumentException();
601 }
602 return true;
603 }
604
605 // PopUpWindow.OnDismissListener#onDismiss
606 public void onDismiss() {
607 notifyOnDismissListener();
608 if (mProvider != null) {
609 mProvider.subUiVisibilityChanged(false);
610 }
611 }
612
613 private void notifyOnDismissListener() {
614 if (mOnDismissListener != null) {
615 mOnDismissListener.onDismiss();
616 }
617 }
618 }
619
620 private static class SetActivated {
621 public static void invoke(View view, boolean activated) {
622 view.setActivated(activated);
623 }
624 }
625
626 private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
627
628 /**
629 * Adapter for backing the list of activities shown in the popup.
630 */
631 private class ActivityChooserViewAdapter extends BaseAdapter {
632
633 public static final int MAX_ACTIVITY_COUNT_UNLIMITED = Integer.MAX_VALUE;
634
635 public static final int MAX_ACTIVITY_COUNT_DEFAULT = 4;
636
637 private static final int ITEM_VIEW_TYPE_ACTIVITY = 0;
638
639 private static final int ITEM_VIEW_TYPE_FOOTER = 1;
640
641 private static final int ITEM_VIEW_TYPE_COUNT = 3;
642
643 private ActivityChooserModel mDataModel;
644
645 private int mMaxActivityCount = MAX_ACTIVITY_COUNT_DEFAULT;
646
647 private boolean mShowDefaultActivity;
648
649 private boolean mHighlightDefaultActivity;
650
651 private boolean mShowFooterView;
652
653 public void setDataModel(ActivityChooserModel dataModel) {
654 ActivityChooserModel oldDataModel = mAdapter.getDataModel();
655 if (oldDataModel != null && isShown()) {
656 try {
657 oldDataModel.unregisterObserver(mModelDataSetOberver);
658 } catch (IllegalStateException e) {
659 //Oh, well... fixes issue #557
660 }
661 }
662 mDataModel = dataModel;
663 if (dataModel != null && isShown()) {
664 dataModel.registerObserver(mModelDataSetOberver);
665 }
666 notifyDataSetChanged();
667 }
668
669 @Override
670 public int getItemViewType(int position) {
671 if (mShowFooterView && position == getCount() - 1) {
672 return ITEM_VIEW_TYPE_FOOTER;
673 } else {
674 return ITEM_VIEW_TYPE_ACTIVITY;
675 }
676 }
677
678 @Override
679 public int getViewTypeCount() {
680 return ITEM_VIEW_TYPE_COUNT;
681 }
682
683 public int getCount() {
684 int count = 0;
685 int activityCount = mDataModel.getActivityCount();
686 if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
687 activityCount--;
688 }
689 count = Math.min(activityCount, mMaxActivityCount);
690 if (mShowFooterView) {
691 count++;
692 }
693 return count;
694 }
695
696 public Object getItem(int position) {
697 final int itemViewType = getItemViewType(position);
698 switch (itemViewType) {
699 case ITEM_VIEW_TYPE_FOOTER:
700 return null;
701 case ITEM_VIEW_TYPE_ACTIVITY:
702 if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
703 position++;
704 }
705 return mDataModel.getActivity(position);
706 default:
707 throw new IllegalArgumentException();
708 }
709 }
710
711 public long getItemId(int position) {
712 return position;
713 }
714
715 public View getView(int position, View convertView, ViewGroup parent) {
716 final int itemViewType = getItemViewType(position);
717 switch (itemViewType) {
718 case ITEM_VIEW_TYPE_FOOTER:
719 if (convertView == null || convertView.getId() != ITEM_VIEW_TYPE_FOOTER) {
720 convertView = LayoutInflater.from(getContext()).inflate(
721 R.layout.abs__activity_chooser_view_list_item, parent, false);
722 convertView.setId(ITEM_VIEW_TYPE_FOOTER);
723 TextView titleView = (TextView) convertView.findViewById(R.id.abs__title);
724 titleView.setText(mContext.getString(
725 R.string.abs__activity_chooser_view_see_all));
726 }
727 return convertView;
728 case ITEM_VIEW_TYPE_ACTIVITY:
729 if (convertView == null || convertView.getId() != R.id.abs__list_item) {
730 convertView = LayoutInflater.from(getContext()).inflate(
731 R.layout.abs__activity_chooser_view_list_item, parent, false);
732 }
733 PackageManager packageManager = mContext.getPackageManager();
734 // Set the icon
735 ImageView iconView = (ImageView) convertView.findViewById(R.id.abs__icon);
736 ResolveInfo activity = (ResolveInfo) getItem(position);
737 iconView.setImageDrawable(activity.loadIcon(packageManager));
738 // Set the title.
739 TextView titleView = (TextView) convertView.findViewById(R.id.abs__title);
740 titleView.setText(activity.loadLabel(packageManager));
741 if (IS_HONEYCOMB) {
742 // Highlight the default.
743 if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) {
744 SetActivated.invoke(convertView, true);
745 } else {
746 SetActivated.invoke(convertView, false);
747 }
748 }
749 return convertView;
750 default:
751 throw new IllegalArgumentException();
752 }
753 }
754
755 public int measureContentWidth() {
756 // The user may have specified some of the target not to be shown but we
757 // want to measure all of them since after expansion they should fit.
758 final int oldMaxActivityCount = mMaxActivityCount;
759 mMaxActivityCount = MAX_ACTIVITY_COUNT_UNLIMITED;
760
761 int contentWidth = 0;
762 View itemView = null;
763
764 final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
765 final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
766 final int count = getCount();
767
768 for (int i = 0; i < count; i++) {
769 itemView = getView(i, itemView, null);
770 itemView.measure(widthMeasureSpec, heightMeasureSpec);
771 contentWidth = Math.max(contentWidth, itemView.getMeasuredWidth());
772 }
773
774 mMaxActivityCount = oldMaxActivityCount;
775
776 return contentWidth;
777 }
778
779 public void setMaxActivityCount(int maxActivityCount) {
780 if (mMaxActivityCount != maxActivityCount) {
781 mMaxActivityCount = maxActivityCount;
782 notifyDataSetChanged();
783 }
784 }
785
786 public ResolveInfo getDefaultActivity() {
787 return mDataModel.getDefaultActivity();
788 }
789
790 public void setShowFooterView(boolean showFooterView) {
791 if (mShowFooterView != showFooterView) {
792 mShowFooterView = showFooterView;
793 notifyDataSetChanged();
794 }
795 }
796
797 public int getActivityCount() {
798 return mDataModel.getActivityCount();
799 }
800
801 public int getHistorySize() {
802 return mDataModel.getHistorySize();
803 }
804
805 public int getMaxActivityCount() {
806 return mMaxActivityCount;
807 }
808
809 public ActivityChooserModel getDataModel() {
810 return mDataModel;
811 }
812
813 public void setShowDefaultActivity(boolean showDefaultActivity,
814 boolean highlightDefaultActivity) {
815 if (mShowDefaultActivity != showDefaultActivity
816 || mHighlightDefaultActivity != highlightDefaultActivity) {
817 mShowDefaultActivity = showDefaultActivity;
818 mHighlightDefaultActivity = highlightDefaultActivity;
819 notifyDataSetChanged();
820 }
821 }
822
823 public boolean getShowDefaultActivity() {
824 return mShowDefaultActivity;
825 }
826 }
827 }