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