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}