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