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