Merge commit '42b2e5ca519766e37ce6941ba4faecc9691cc403' into upstream
[debian/openrocket] / android-libraries / ActionBarSherlock / src / com / actionbarsherlock / widget / ActivityChooserView.java
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/widget/ActivityChooserView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/widget/ActivityChooserView.java
new file mode 100644 (file)
index 0000000..da13bc9
--- /dev/null
@@ -0,0 +1,818 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.widget;
+
+import android.os.Build;
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.internal.widget.IcsLinearLayout;
+import com.actionbarsherlock.internal.widget.IcsListPopupWindow;
+import com.actionbarsherlock.view.ActionProvider;
+import com.actionbarsherlock.widget.ActivityChooserModel.ActivityChooserModelClient;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.PopupWindow;
+import android.widget.TextView;
+
+/**
+ * This class is a view for choosing an activity for handling a given {@link Intent}.
+ * <p>
+ * The view is composed of two adjacent buttons:
+ * <ul>
+ * <li>
+ * The left button is an immediate action and allows one click activity choosing.
+ * Tapping this button immediately executes the intent without requiring any further
+ * user input. Long press on this button shows a popup for changing the default
+ * activity.
+ * </li>
+ * <li>
+ * The right button is an overflow action and provides an optimized menu
+ * of additional activities. Tapping this button shows a popup anchored to this
+ * view, listing the most frequently used activities. This list is initially
+ * limited to a small number of items in frequency used order. The last item,
+ * "Show all..." serves as an affordance to display all available activities.
+ * </li>
+ * </ul>
+ * </p>
+ *
+ * @hide
+ */
+class ActivityChooserView extends ViewGroup implements ActivityChooserModelClient {
+
+    /**
+     * An adapter for displaying the activities in an {@link AdapterView}.
+     */
+    private final ActivityChooserViewAdapter mAdapter;
+
+    /**
+     * Implementation of various interfaces to avoid publishing them in the APIs.
+     */
+    private final Callbacks mCallbacks;
+
+    /**
+     * The content of this view.
+     */
+    private final IcsLinearLayout mActivityChooserContent;
+
+    /**
+     * Stores the background drawable to allow hiding and latter showing.
+     */
+    private final Drawable mActivityChooserContentBackground;
+
+    /**
+     * The expand activities action button;
+     */
+    private final FrameLayout mExpandActivityOverflowButton;
+
+    /**
+     * The image for the expand activities action button;
+     */
+    private final ImageView mExpandActivityOverflowButtonImage;
+
+    /**
+     * The default activities action button;
+     */
+    private final FrameLayout mDefaultActivityButton;
+
+    /**
+     * The image for the default activities action button;
+     */
+    private final ImageView mDefaultActivityButtonImage;
+
+    /**
+     * The maximal width of the list popup.
+     */
+    private final int mListPopupMaxWidth;
+
+    /**
+     * The ActionProvider hosting this view, if applicable.
+     */
+    ActionProvider mProvider;
+
+    /**
+     * Observer for the model data.
+     */
+    private final DataSetObserver mModelDataSetOberver = new DataSetObserver() {
+
+        @Override
+        public void onChanged() {
+            super.onChanged();
+            mAdapter.notifyDataSetChanged();
+        }
+        @Override
+        public void onInvalidated() {
+            super.onInvalidated();
+            mAdapter.notifyDataSetInvalidated();
+        }
+    };
+
+    private final OnGlobalLayoutListener mOnGlobalLayoutListener = new OnGlobalLayoutListener() {
+        @Override
+        public void onGlobalLayout() {
+            if (isShowingPopup()) {
+                if (!isShown()) {
+                    getListPopupWindow().dismiss();
+                } else {
+                    getListPopupWindow().show();
+                    if (mProvider != null) {
+                        mProvider.subUiVisibilityChanged(true);
+                    }
+                }
+            }
+        }
+    };
+
+    /**
+     * Popup window for showing the activity overflow list.
+     */
+    private IcsListPopupWindow mListPopupWindow;
+
+    /**
+     * Listener for the dismissal of the popup/alert.
+     */
+    private PopupWindow.OnDismissListener mOnDismissListener;
+
+    /**
+     * Flag whether a default activity currently being selected.
+     */
+    private boolean mIsSelectingDefaultActivity;
+
+    /**
+     * The count of activities in the popup.
+     */
+    private int mInitialActivityCount = ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_DEFAULT;
+
+    /**
+     * Flag whether this view is attached to a window.
+     */
+    private boolean mIsAttachedToWindow;
+
+    /**
+     * String resource for formatting content description of the default target.
+     */
+    private int mDefaultActionButtonContentDescription;
+
+    private final Context mContext;
+
+    /**
+     * Create a new instance.
+     *
+     * @param context The application environment.
+     */
+    public ActivityChooserView(Context context) {
+        this(context, null);
+    }
+
+    /**
+     * Create a new instance.
+     *
+     * @param context The application environment.
+     * @param attrs A collection of attributes.
+     */
+    public ActivityChooserView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    /**
+     * Create a new instance.
+     *
+     * @param context The application environment.
+     * @param attrs A collection of attributes.
+     * @param defStyle The default style to apply to this view.
+     */
+    public ActivityChooserView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mContext = context;
+
+        TypedArray attributesArray = context.obtainStyledAttributes(attrs,
+                R.styleable.SherlockActivityChooserView, defStyle, 0);
+
+        mInitialActivityCount = attributesArray.getInt(
+                R.styleable.SherlockActivityChooserView_initialActivityCount,
+                ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_DEFAULT);
+
+        Drawable expandActivityOverflowButtonDrawable = attributesArray.getDrawable(
+                R.styleable.SherlockActivityChooserView_expandActivityOverflowButtonDrawable);
+
+        attributesArray.recycle();
+
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        inflater.inflate(R.layout.abs__activity_chooser_view, this, true);
+
+        mCallbacks = new Callbacks();
+
+        mActivityChooserContent = (IcsLinearLayout) findViewById(R.id.abs__activity_chooser_view_content);
+        mActivityChooserContentBackground = mActivityChooserContent.getBackground();
+
+        mDefaultActivityButton = (FrameLayout) findViewById(R.id.abs__default_activity_button);
+        mDefaultActivityButton.setOnClickListener(mCallbacks);
+        mDefaultActivityButton.setOnLongClickListener(mCallbacks);
+        mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.abs__image);
+
+        mExpandActivityOverflowButton = (FrameLayout) findViewById(R.id.abs__expand_activities_button);
+        mExpandActivityOverflowButton.setOnClickListener(mCallbacks);
+        mExpandActivityOverflowButtonImage =
+            (ImageView) mExpandActivityOverflowButton.findViewById(R.id.abs__image);
+        mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable);
+
+        mAdapter = new ActivityChooserViewAdapter();
+        mAdapter.registerDataSetObserver(new DataSetObserver() {
+            @Override
+            public void onChanged() {
+                super.onChanged();
+                updateAppearance();
+            }
+        });
+
+        Resources resources = context.getResources();
+        mListPopupMaxWidth = Math.max(resources.getDisplayMetrics().widthPixels / 2,
+              resources.getDimensionPixelSize(R.dimen.abs__config_prefDialogWidth));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setActivityChooserModel(ActivityChooserModel dataModel) {
+        mAdapter.setDataModel(dataModel);
+        if (isShowingPopup()) {
+            dismissPopup();
+            showPopup();
+        }
+    }
+
+    /**
+     * Sets the background for the button that expands the activity
+     * overflow list.
+     *
+     * <strong>Note:</strong> Clients would like to set this drawable
+     * as a clue about the action the chosen activity will perform. For
+     * example, if a share activity is to be chosen the drawable should
+     * give a clue that sharing is to be performed.
+     *
+     * @param drawable The drawable.
+     */
+    public void setExpandActivityOverflowButtonDrawable(Drawable drawable) {
+        mExpandActivityOverflowButtonImage.setImageDrawable(drawable);
+    }
+
+    /**
+     * Sets the content description for the button that expands the activity
+     * overflow list.
+     *
+     * description as a clue about the action performed by the button.
+     * For example, if a share activity is to be chosen the content
+     * description should be something like "Share with".
+     *
+     * @param resourceId The content description resource id.
+     */
+    public void setExpandActivityOverflowButtonContentDescription(int resourceId) {
+        CharSequence contentDescription = mContext.getString(resourceId);
+        mExpandActivityOverflowButtonImage.setContentDescription(contentDescription);
+    }
+
+    /**
+     * Set the provider hosting this view, if applicable.
+     * @hide Internal use only
+     */
+    public void setProvider(ActionProvider provider) {
+        mProvider = provider;
+    }
+
+    /**
+     * Shows the popup window with activities.
+     *
+     * @return True if the popup was shown, false if already showing.
+     */
+    public boolean showPopup() {
+        if (isShowingPopup() || !mIsAttachedToWindow) {
+            return false;
+        }
+        mIsSelectingDefaultActivity = false;
+        showPopupUnchecked(mInitialActivityCount);
+        return true;
+    }
+
+    /**
+     * Shows the popup no matter if it was already showing.
+     *
+     * @param maxActivityCount The max number of activities to display.
+     */
+    private void showPopupUnchecked(int maxActivityCount) {
+        if (mAdapter.getDataModel() == null) {
+            throw new IllegalStateException("No data model. Did you call #setDataModel?");
+        }
+
+        getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
+
+        final boolean defaultActivityButtonShown =
+            mDefaultActivityButton.getVisibility() == VISIBLE;
+
+        final int activityCount = mAdapter.getActivityCount();
+        final int maxActivityCountOffset = defaultActivityButtonShown ? 1 : 0;
+        if (maxActivityCount != ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED
+                && activityCount > maxActivityCount + maxActivityCountOffset) {
+            mAdapter.setShowFooterView(true);
+            mAdapter.setMaxActivityCount(maxActivityCount - 1);
+        } else {
+            mAdapter.setShowFooterView(false);
+            mAdapter.setMaxActivityCount(maxActivityCount);
+        }
+
+        IcsListPopupWindow popupWindow = getListPopupWindow();
+        if (!popupWindow.isShowing()) {
+            if (mIsSelectingDefaultActivity || !defaultActivityButtonShown) {
+                mAdapter.setShowDefaultActivity(true, defaultActivityButtonShown);
+            } else {
+                mAdapter.setShowDefaultActivity(false, false);
+            }
+            final int contentWidth = Math.min(mAdapter.measureContentWidth(), mListPopupMaxWidth);
+            popupWindow.setContentWidth(contentWidth);
+            popupWindow.show();
+            if (mProvider != null) {
+                mProvider.subUiVisibilityChanged(true);
+            }
+            popupWindow.getListView().setContentDescription(mContext.getString(
+                    R.string.abs__activitychooserview_choose_application));
+        }
+    }
+
+    /**
+     * Dismisses the popup window with activities.
+     *
+     * @return True if dismissed, false if already dismissed.
+     */
+    public boolean dismissPopup() {
+        if (isShowingPopup()) {
+            getListPopupWindow().dismiss();
+            ViewTreeObserver viewTreeObserver = getViewTreeObserver();
+            if (viewTreeObserver.isAlive()) {
+                viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Gets whether the popup window with activities is shown.
+     *
+     * @return True if the popup is shown.
+     */
+    public boolean isShowingPopup() {
+        return getListPopupWindow().isShowing();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        ActivityChooserModel dataModel = mAdapter.getDataModel();
+        if (dataModel != null) {
+            dataModel.registerObserver(mModelDataSetOberver);
+        }
+        mIsAttachedToWindow = true;
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        ActivityChooserModel dataModel = mAdapter.getDataModel();
+        if (dataModel != null) {
+            dataModel.unregisterObserver(mModelDataSetOberver);
+        }
+        ViewTreeObserver viewTreeObserver = getViewTreeObserver();
+        if (viewTreeObserver.isAlive()) {
+            viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
+        }
+        mIsAttachedToWindow = false;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        View child = mActivityChooserContent;
+        // If the default action is not visible we want to be as tall as the
+        // ActionBar so if this widget is used in the latter it will look as
+        // a normal action button.
+        if (mDefaultActivityButton.getVisibility() != VISIBLE) {
+            heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
+                    MeasureSpec.EXACTLY);
+        }
+        measureChild(child, widthMeasureSpec, heightMeasureSpec);
+        setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        mActivityChooserContent.layout(0, 0, right - left, bottom - top);
+        if (getListPopupWindow().isShowing()) {
+            showPopupUnchecked(mAdapter.getMaxActivityCount());
+        } else {
+            dismissPopup();
+        }
+    }
+
+    public ActivityChooserModel getDataModel() {
+        return mAdapter.getDataModel();
+    }
+
+    /**
+     * Sets a listener to receive a callback when the popup is dismissed.
+     *
+     * @param listener The listener to be notified.
+     */
+    public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
+        mOnDismissListener = listener;
+    }
+
+    /**
+     * Sets the initial count of items shown in the activities popup
+     * i.e. the items before the popup is expanded. This is an upper
+     * bound since it is not guaranteed that such number of intent
+     * handlers exist.
+     *
+     * @param itemCount The initial popup item count.
+     */
+    public void setInitialActivityCount(int itemCount) {
+        mInitialActivityCount = itemCount;
+    }
+
+    /**
+     * Sets a content description of the default action button. This
+     * resource should be a string taking one formatting argument and
+     * will be used for formatting the content description of the button
+     * dynamically as the default target changes. For example, a resource
+     * pointing to the string "share with %1$s" will result in a content
+     * description "share with Bluetooth" for the Bluetooth activity.
+     *
+     * @param resourceId The resource id.
+     */
+    public void setDefaultActionButtonContentDescription(int resourceId) {
+        mDefaultActionButtonContentDescription = resourceId;
+    }
+
+    /**
+     * Gets the list popup window which is lazily initialized.
+     *
+     * @return The popup.
+     */
+    private IcsListPopupWindow getListPopupWindow() {
+        if (mListPopupWindow == null) {
+            mListPopupWindow = new IcsListPopupWindow(getContext());
+            mListPopupWindow.setAdapter(mAdapter);
+            mListPopupWindow.setAnchorView(ActivityChooserView.this);
+            mListPopupWindow.setModal(true);
+            mListPopupWindow.setOnItemClickListener(mCallbacks);
+            mListPopupWindow.setOnDismissListener(mCallbacks);
+        }
+        return mListPopupWindow;
+    }
+
+    /**
+     * Updates the buttons state.
+     */
+    private void updateAppearance() {
+        // Expand overflow button.
+        if (mAdapter.getCount() > 0) {
+            mExpandActivityOverflowButton.setEnabled(true);
+        } else {
+            mExpandActivityOverflowButton.setEnabled(false);
+        }
+        // Default activity button.
+        final int activityCount = mAdapter.getActivityCount();
+        final int historySize = mAdapter.getHistorySize();
+        if (activityCount > 0 && historySize > 0) {
+            mDefaultActivityButton.setVisibility(VISIBLE);
+            ResolveInfo activity = mAdapter.getDefaultActivity();
+            PackageManager packageManager = mContext.getPackageManager();
+            mDefaultActivityButtonImage.setImageDrawable(activity.loadIcon(packageManager));
+            if (mDefaultActionButtonContentDescription != 0) {
+                CharSequence label = activity.loadLabel(packageManager);
+                String contentDescription = mContext.getString(
+                        mDefaultActionButtonContentDescription, label);
+                mDefaultActivityButton.setContentDescription(contentDescription);
+            }
+        } else {
+            mDefaultActivityButton.setVisibility(View.GONE);
+        }
+        // Activity chooser content.
+        if (mDefaultActivityButton.getVisibility() == VISIBLE) {
+            mActivityChooserContent.setBackgroundDrawable(mActivityChooserContentBackground);
+        } else {
+            mActivityChooserContent.setBackgroundDrawable(null);
+        }
+    }
+
+    /**
+     * Interface implementation to avoid publishing them in the APIs.
+     */
+    private class Callbacks implements AdapterView.OnItemClickListener,
+            View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener {
+
+        // AdapterView#OnItemClickListener
+        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+            ActivityChooserViewAdapter adapter = (ActivityChooserViewAdapter) parent.getAdapter();
+            final int itemViewType = adapter.getItemViewType(position);
+            switch (itemViewType) {
+                case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_FOOTER: {
+                    showPopupUnchecked(ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED);
+                } break;
+                case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_ACTIVITY: {
+                    dismissPopup();
+                    if (mIsSelectingDefaultActivity) {
+                        // The item at position zero is the default already.
+                        if (position > 0) {
+                            mAdapter.getDataModel().setDefaultActivity(position);
+                        }
+                    } else {
+                        // If the default target is not shown in the list, the first
+                        // item in the model is default action => adjust index
+                        position = mAdapter.getShowDefaultActivity() ? position : position + 1;
+                        Intent launchIntent = mAdapter.getDataModel().chooseActivity(position);
+                        if (launchIntent != null) {
+                            mContext.startActivity(launchIntent);
+                        }
+                    }
+                } break;
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+
+        // View.OnClickListener
+        public void onClick(View view) {
+            if (view == mDefaultActivityButton) {
+                dismissPopup();
+                ResolveInfo defaultActivity = mAdapter.getDefaultActivity();
+                final int index = mAdapter.getDataModel().getActivityIndex(defaultActivity);
+                Intent launchIntent = mAdapter.getDataModel().chooseActivity(index);
+                if (launchIntent != null) {
+                    mContext.startActivity(launchIntent);
+                }
+            } else if (view == mExpandActivityOverflowButton) {
+                mIsSelectingDefaultActivity = false;
+                showPopupUnchecked(mInitialActivityCount);
+            } else {
+                throw new IllegalArgumentException();
+            }
+        }
+
+        // OnLongClickListener#onLongClick
+        @Override
+        public boolean onLongClick(View view) {
+            if (view == mDefaultActivityButton) {
+                if (mAdapter.getCount() > 0) {
+                    mIsSelectingDefaultActivity = true;
+                    showPopupUnchecked(mInitialActivityCount);
+                }
+            } else {
+                throw new IllegalArgumentException();
+            }
+            return true;
+        }
+
+        // PopUpWindow.OnDismissListener#onDismiss
+        public void onDismiss() {
+            notifyOnDismissListener();
+            if (mProvider != null) {
+                mProvider.subUiVisibilityChanged(false);
+            }
+        }
+
+        private void notifyOnDismissListener() {
+            if (mOnDismissListener != null) {
+                mOnDismissListener.onDismiss();
+            }
+        }
+    }
+
+    private static class SetActivated {
+        public static void invoke(View view, boolean activated) {
+            view.setActivated(activated);
+        }
+    }
+
+    private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
+
+    /**
+     * Adapter for backing the list of activities shown in the popup.
+     */
+    private class ActivityChooserViewAdapter extends BaseAdapter {
+
+        public static final int MAX_ACTIVITY_COUNT_UNLIMITED = Integer.MAX_VALUE;
+
+        public static final int MAX_ACTIVITY_COUNT_DEFAULT = 4;
+
+        private static final int ITEM_VIEW_TYPE_ACTIVITY = 0;
+
+        private static final int ITEM_VIEW_TYPE_FOOTER = 1;
+
+        private static final int ITEM_VIEW_TYPE_COUNT = 3;
+
+        private ActivityChooserModel mDataModel;
+
+        private int mMaxActivityCount = MAX_ACTIVITY_COUNT_DEFAULT;
+
+        private boolean mShowDefaultActivity;
+
+        private boolean mHighlightDefaultActivity;
+
+        private boolean mShowFooterView;
+
+        public void setDataModel(ActivityChooserModel dataModel) {
+            ActivityChooserModel oldDataModel = mAdapter.getDataModel();
+            if (oldDataModel != null && isShown()) {
+                oldDataModel.unregisterObserver(mModelDataSetOberver);
+            }
+            mDataModel = dataModel;
+            if (dataModel != null && isShown()) {
+                dataModel.registerObserver(mModelDataSetOberver);
+            }
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            if (mShowFooterView && position == getCount() - 1) {
+                return ITEM_VIEW_TYPE_FOOTER;
+            } else {
+                return ITEM_VIEW_TYPE_ACTIVITY;
+            }
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return ITEM_VIEW_TYPE_COUNT;
+        }
+
+        public int getCount() {
+            int count = 0;
+            int activityCount = mDataModel.getActivityCount();
+            if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
+                activityCount--;
+            }
+            count = Math.min(activityCount, mMaxActivityCount);
+            if (mShowFooterView) {
+                count++;
+            }
+            return count;
+        }
+
+        public Object getItem(int position) {
+            final int itemViewType = getItemViewType(position);
+            switch (itemViewType) {
+                case ITEM_VIEW_TYPE_FOOTER:
+                    return null;
+                case ITEM_VIEW_TYPE_ACTIVITY:
+                    if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
+                        position++;
+                    }
+                    return mDataModel.getActivity(position);
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final int itemViewType = getItemViewType(position);
+            switch (itemViewType) {
+                case ITEM_VIEW_TYPE_FOOTER:
+                    if (convertView == null || convertView.getId() != ITEM_VIEW_TYPE_FOOTER) {
+                        convertView = LayoutInflater.from(getContext()).inflate(
+                                R.layout.abs__activity_chooser_view_list_item, parent, false);
+                        convertView.setId(ITEM_VIEW_TYPE_FOOTER);
+                        TextView titleView = (TextView) convertView.findViewById(R.id.abs__title);
+                        titleView.setText(mContext.getString(
+                                R.string.abs__activity_chooser_view_see_all));
+                    }
+                    return convertView;
+                case ITEM_VIEW_TYPE_ACTIVITY:
+                    if (convertView == null || convertView.getId() != R.id.abs__list_item) {
+                        convertView = LayoutInflater.from(getContext()).inflate(
+                                R.layout.abs__activity_chooser_view_list_item, parent, false);
+                    }
+                    PackageManager packageManager = mContext.getPackageManager();
+                    // Set the icon
+                    ImageView iconView = (ImageView) convertView.findViewById(R.id.abs__icon);
+                    ResolveInfo activity = (ResolveInfo) getItem(position);
+                    iconView.setImageDrawable(activity.loadIcon(packageManager));
+                    // Set the title.
+                    TextView titleView = (TextView) convertView.findViewById(R.id.abs__title);
+                    titleView.setText(activity.loadLabel(packageManager));
+                    if (IS_HONEYCOMB) {
+                        // Highlight the default.
+                        if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) {
+                            SetActivated.invoke(convertView, true);
+                        } else {
+                            SetActivated.invoke(convertView, false);
+                        }
+                    }
+                    return convertView;
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+
+        public int measureContentWidth() {
+            // The user may have specified some of the target not to be shown but we
+            // want to measure all of them since after expansion they should fit.
+            final int oldMaxActivityCount = mMaxActivityCount;
+            mMaxActivityCount = MAX_ACTIVITY_COUNT_UNLIMITED;
+
+            int contentWidth = 0;
+            View itemView = null;
+
+            final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            final int count = getCount();
+
+            for (int i = 0; i < count; i++) {
+                itemView = getView(i, itemView, null);
+                itemView.measure(widthMeasureSpec, heightMeasureSpec);
+                contentWidth = Math.max(contentWidth, itemView.getMeasuredWidth());
+            }
+
+            mMaxActivityCount = oldMaxActivityCount;
+
+            return contentWidth;
+        }
+
+        public void setMaxActivityCount(int maxActivityCount) {
+            if (mMaxActivityCount != maxActivityCount) {
+                mMaxActivityCount = maxActivityCount;
+                notifyDataSetChanged();
+            }
+        }
+
+        public ResolveInfo getDefaultActivity() {
+            return mDataModel.getDefaultActivity();
+        }
+
+        public void setShowFooterView(boolean showFooterView) {
+            if (mShowFooterView != showFooterView) {
+                mShowFooterView = showFooterView;
+                notifyDataSetChanged();
+            }
+        }
+
+        public int getActivityCount() {
+            return mDataModel.getActivityCount();
+        }
+
+        public int getHistorySize() {
+            return mDataModel.getHistorySize();
+        }
+
+        public int getMaxActivityCount() {
+            return mMaxActivityCount;
+        }
+
+        public ActivityChooserModel getDataModel() {
+            return mDataModel;
+        }
+
+        public void setShowDefaultActivity(boolean showDefaultActivity,
+                boolean highlightDefaultActivity) {
+            if (mShowDefaultActivity != showDefaultActivity
+                    || mHighlightDefaultActivity != highlightDefaultActivity) {
+                mShowDefaultActivity = showDefaultActivity;
+                mHighlightDefaultActivity = highlightDefaultActivity;
+                notifyDataSetChanged();
+            }
+        }
+
+        public boolean getShowDefaultActivity() {
+            return mShowDefaultActivity;
+        }
+    }
+}