PhoneWindow.java revision 64da12ab1f472e01325b6c6d094153ac110eaf7b
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License"); 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * you may not use this file except in compliance with the License. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * You may obtain a copy of the License at 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * http://www.apache.org/licenses/LICENSE-2.0 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Unless required by applicable law or agreed to in writing, software 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS, 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * See the License for the specific language governing permissions and 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * limitations under the License. 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package com.android.internal.policy.impl; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import static android.view.WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import com.android.internal.view.BaseSurfaceHolder; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import com.android.internal.view.RootViewSurfaceTaker; 293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import com.android.internal.view.StandaloneActionMode; 303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import com.android.internal.view.menu.ContextMenuBuilder; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import com.android.internal.view.menu.MenuBuilder; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import com.android.internal.view.menu.MenuDialogHelper; 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import com.android.internal.view.menu.MenuPopupHelper; 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import com.android.internal.view.menu.MenuView; 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import com.android.internal.view.menu.SubMenuBuilder; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import com.android.internal.widget.ActionBarContextView; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import com.android.internal.widget.ActionBarView; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.app.KeyguardManager; 40bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochimport android.content.Context; 413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.content.res.Configuration; 423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.content.res.TypedArray; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.graphics.Canvas; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.graphics.PixelFormat; 457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport android.graphics.Rect; 467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport android.graphics.drawable.Drawable; 477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport android.media.AudioManager; 48558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochimport android.net.Uri; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Bundle; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Parcel; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Parcelable; 5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.util.AndroidRuntimeException; 537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport android.util.Config; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.EventLog; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Log; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.SparseArray; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.TypedValue; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.ActionMode; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.Gravity; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.HardwareRenderer; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.InputQueue; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.KeyCharacterMap; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.KeyEvent; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.LayoutInflater; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.Menu; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.MenuItem; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.MotionEvent; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.SurfaceHolder; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.View; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.ViewGroup; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.ViewManager; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.ViewStub; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.Window; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.WindowManager; 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.accessibility.AccessibilityEvent; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.accessibility.AccessibilityManager; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.animation.Animation; 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import android.view.animation.AnimationUtils; 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import android.widget.FrameLayout; 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import android.widget.ImageView; 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import android.widget.PopupWindow; 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import android.widget.ProgressBar; 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import android.widget.TextView; 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/** 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Android-specific Window. 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * <p> 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * todo: need to pull the generic functionality out into a base class 894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * in android.widget. 904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */ 914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)public class PhoneWindow extends Window implements MenuBuilder.Callback { 924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private final static String TAG = "PhoneWindow"; 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private final static boolean SWEEP_OPEN_MENU = false; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Simple callback used by the context menu and its submenus. The options 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * menu submenus do not use this (their behavior is more complex). 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DialogMenuCallback mContextMenuCallback = new DialogMenuCallback(FEATURE_CONTEXT_MENU); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is the top-level view of the window, containing the window decor. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private DecorView mDecor; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is the view in which the window contents are placed. It is either 10723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // mDecor itself, or a child of mDecor where the contents go. 10823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) private ViewGroup mContentParent; 10923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 11023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) SurfaceHolder.Callback2 mTakeSurfaceCallback; 11123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) BaseSurfaceHolder mSurfaceHolder; 11223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 11323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) InputQueue.Callback mTakeInputQueueCallback; 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 11523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) private boolean mIsFloating; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private LayoutInflater mLayoutInflater; 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private TextView mTitleView; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private ActionBarView mActionBar; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private DrawableFeatureState[] mDrawables; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private PanelFeatureState[] mPanels; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The panel that is prepared or opened (the most recent one if there are 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * multiple panels). Shortcuts will go to this panel. It gets set in 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * {@link #preparePanel} and cleared in {@link #closePanel}. 1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */ 1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private PanelFeatureState mPreparedPanel; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) /** 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * The keycode that is currently held down (as a modifier) for chording. If 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * this is 0, there is no key held down. 13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) */ 13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private int mPanelChordingKey; 1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private boolean mPanelMayLongPress; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 141bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch private ImageView mLeftIconView; 142bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private ImageView mRightIconView; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private ProgressBar mCircularProgressBar; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 147558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch private ProgressBar mHorizontalProgressBar; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private int mBackgroundResource = 0; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private Drawable mBackgroundDrawable; 1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch private int mFrameResource = 0; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private int mTextColor = 0; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private CharSequence mTitle = null; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private int mTitleColor = 0; 1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private ContextMenuBuilder mContextMenu; 1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private MenuDialogHelper mContextMenuHelper; 163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private ActionButtonSubmenu mActionButtonPopup; 164558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch private boolean mClosingActionMenu; 165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 16623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; 16723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 16823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) private AudioManager mAudioManager; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private KeyguardManager mKeyguardManager; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public PhoneWindow(Context context) { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) super(context); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mLayoutInflater = LayoutInflater.from(context); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public final void setContainer(Window container) { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) super.setContainer(container); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public boolean requestFeature(int featureId) { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mContentParent != null) { 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new AndroidRuntimeException("requestFeature() must be called before adding content"); 185558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch } 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) final int features = getFeatures(); 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((features != DEFAULT_FEATURES) && (featureId == FEATURE_CUSTOM_TITLE)) { 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Another feature is enabled and the user is trying to enable the custom title feature */ 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) throw new AndroidRuntimeException("You cannot combine custom titles with other title features"); 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) && (featureId != FEATURE_CUSTOM_TITLE)) { 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 19423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) /* Custom title feature is enabled and the user is trying to enable another feature */ 19523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) throw new AndroidRuntimeException("You cannot combine custom titles with other title features"); 19623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 19723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if ((features & (1 << FEATURE_NO_TITLE)) != 0 && featureId == FEATURE_ACTION_BAR) { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; // Ignore. No title dominates. 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_NO_TITLE) { 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove the action bar feature if we have no title. No title dominates. 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) removeFeature(FEATURE_ACTION_BAR); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 204 return super.requestFeature(featureId); 205 } 206 207 @Override 208 public void setContentView(int layoutResID) { 209 if (mContentParent == null) { 210 installDecor(); 211 } else { 212 mContentParent.removeAllViews(); 213 } 214 mLayoutInflater.inflate(layoutResID, mContentParent); 215 final Callback cb = getCallback(); 216 if (cb != null) { 217 cb.onContentChanged(); 218 } 219 } 220 221 @Override 222 public void setContentView(View view) { 223 setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); 224 } 225 226 @Override 227 public void setContentView(View view, ViewGroup.LayoutParams params) { 228 if (mContentParent == null) { 229 installDecor(); 230 } else { 231 mContentParent.removeAllViews(); 232 } 233 mContentParent.addView(view, params); 234 final Callback cb = getCallback(); 235 if (cb != null) { 236 cb.onContentChanged(); 237 } 238 } 239 240 @Override 241 public void addContentView(View view, ViewGroup.LayoutParams params) { 242 if (mContentParent == null) { 243 installDecor(); 244 } 245 mContentParent.addView(view, params); 246 final Callback cb = getCallback(); 247 if (cb != null) { 248 cb.onContentChanged(); 249 } 250 } 251 252 @Override 253 public View getCurrentFocus() { 254 return mDecor != null ? mDecor.findFocus() : null; 255 } 256 257 @Override 258 public void takeSurface(SurfaceHolder.Callback2 callback) { 259 mTakeSurfaceCallback = callback; 260 } 261 262 public void takeInputQueue(InputQueue.Callback callback) { 263 mTakeInputQueueCallback = callback; 264 } 265 266 @Override 267 public boolean isFloating() { 268 return mIsFloating; 269 } 270 271 /** 272 * Return a LayoutInflater instance that can be used to inflate XML view layout 273 * resources for use in this Window. 274 * 275 * @return LayoutInflater The shared LayoutInflater. 276 */ 277 @Override 278 public LayoutInflater getLayoutInflater() { 279 return mLayoutInflater; 280 } 281 282 @Override 283 public void setTitle(CharSequence title) { 284 if (mTitleView != null) { 285 mTitleView.setText(title); 286 } else if (mActionBar != null) { 287 mActionBar.setWindowTitle(title); 288 } 289 mTitle = title; 290 } 291 292 @Override 293 public void setTitleColor(int textColor) { 294 if (mTitleView != null) { 295 mTitleView.setTextColor(textColor); 296 } 297 mTitleColor = textColor; 298 } 299 300 /** 301 * Prepares the panel to either be opened or chorded. This creates the Menu 302 * instance for the panel and populates it via the Activity callbacks. 303 * 304 * @param st The panel state to prepare. 305 * @param event The event that triggered the preparing of the panel. 306 * @return Whether the panel was prepared. If the panel should not be shown, 307 * returns false. 308 */ 309 public final boolean preparePanel(PanelFeatureState st, KeyEvent event) { 310 // Already prepared (isPrepared will be reset to false later) 311 if (st.isPrepared) 312 return true; 313 314 if ((mPreparedPanel != null) && (mPreparedPanel != st)) { 315 // Another Panel is prepared and possibly open, so close it 316 closePanel(mPreparedPanel, false); 317 } 318 319 final Callback cb = getCallback(); 320 321 if (cb != null) { 322 st.createdPanelView = cb.onCreatePanelView(st.featureId); 323 } 324 325 if (st.createdPanelView == null) { 326 // Init the panel state's menu--return false if init failed 327 if (st.menu == null || st.refreshMenuContent) { 328 if (st.menu == null) { 329 if (!initializePanelMenu(st) || (st.menu == null)) { 330 return false; 331 } 332 } 333 // Call callback, and return if it doesn't want to display menu 334 if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) { 335 // Ditch the menu created above 336 st.menu = null; 337 338 return false; 339 } 340 341 st.refreshMenuContent = false; 342 343 if (mActionBar != null) { 344 mActionBar.setMenu(st.menu); 345 } 346 } 347 348 // Callback and return if the callback does not want to show the menu 349 if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) { 350 return false; 351 } 352 353 // Set the proper keymap 354 KeyCharacterMap kmap = KeyCharacterMap.load( 355 event != null ? event.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD); 356 st.qwertyMode = kmap.getKeyboardType() != KeyCharacterMap.NUMERIC; 357 st.menu.setQwertyMode(st.qwertyMode); 358 } 359 360 // Set other state 361 st.isPrepared = true; 362 st.isHandled = false; 363 mPreparedPanel = st; 364 365 return true; 366 } 367 368 @Override 369 public void onConfigurationChanged(Configuration newConfig) { 370 // Action bars handle their own menu state 371 if (mActionBar == null) { 372 PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); 373 if ((st != null) && (st.menu != null)) { 374 final MenuBuilder menuBuilder = (MenuBuilder) st.menu; 375 376 if (st.isOpen) { 377 // Freeze state 378 final Bundle state = new Bundle(); 379 menuBuilder.saveHierarchyState(state); 380 381 // Remove the menu views since they need to be recreated 382 // according to the new configuration 383 clearMenuViews(st); 384 385 // Re-open the same menu 386 reopenMenu(false); 387 388 // Restore state 389 menuBuilder.restoreHierarchyState(state); 390 391 } else { 392 // Clear menu views so on next menu opening, it will use 393 // the proper layout 394 clearMenuViews(st); 395 } 396 } 397 } 398 } 399 400 private static void clearMenuViews(PanelFeatureState st) { 401 // This can be called on config changes, so we should make sure 402 // the views will be reconstructed based on the new orientation, etc. 403 404 // Allow the callback to create a new panel view 405 st.createdPanelView = null; 406 407 // Causes the decor view to be recreated 408 st.refreshDecorView = true; 409 410 ((MenuBuilder) st.menu).clearMenuViews(); 411 } 412 413 @Override 414 public final void openPanel(int featureId, KeyEvent event) { 415 if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && 416 mActionBar.isOverflowReserved()) { 417 // Invalidate the options menu, we want a prepare event that the app can respond to. 418 invalidatePanelMenu(FEATURE_OPTIONS_PANEL); 419 mActionBar.showOverflowMenu(); 420 } else { 421 openPanel(getPanelState(featureId, true), event); 422 } 423 } 424 425 private void openPanel(PanelFeatureState st, KeyEvent event) { 426 // System.out.println("Open panel: isOpen=" + st.isOpen); 427 428 // Already open, return 429 if (st.isOpen) { 430 return; 431 } 432 433 Callback cb = getCallback(); 434 if ((cb != null) && (!cb.onMenuOpened(st.featureId, st.menu))) { 435 // Callback doesn't want the menu to open, reset any state 436 closePanel(st, true); 437 return; 438 } 439 440 final WindowManager wm = getWindowManager(); 441 if (wm == null) { 442 return; 443 } 444 445 // Prepare panel (should have been done before, but just in case) 446 if (!preparePanel(st, event)) { 447 return; 448 } 449 450 if (st.decorView == null || st.refreshDecorView) { 451 if (st.decorView == null) { 452 // Initialize the panel decor, this will populate st.decorView 453 if (!initializePanelDecor(st) || (st.decorView == null)) 454 return; 455 } else if (st.refreshDecorView && (st.decorView.getChildCount() > 0)) { 456 // Decor needs refreshing, so remove its views 457 st.decorView.removeAllViews(); 458 } 459 460 // This will populate st.shownPanelView 461 if (!initializePanelContent(st) || (st.shownPanelView == null)) { 462 return; 463 } 464 465 ViewGroup.LayoutParams lp = st.shownPanelView.getLayoutParams(); 466 if (lp == null) { 467 lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); 468 } 469 470 int backgroundResId; 471 if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT) { 472 // If the contents is fill parent for the width, set the 473 // corresponding background 474 backgroundResId = st.fullBackground; 475 } else { 476 // Otherwise, set the normal panel background 477 backgroundResId = st.background; 478 } 479 st.decorView.setWindowBackground(getContext().getResources().getDrawable( 480 backgroundResId)); 481 482 483 st.decorView.addView(st.shownPanelView, lp); 484 485 /* 486 * Give focus to the view, if it or one of its children does not 487 * already have it. 488 */ 489 if (!st.shownPanelView.hasFocus()) { 490 st.shownPanelView.requestFocus(); 491 } 492 } 493 494 st.isOpen = true; 495 st.isHandled = false; 496 497 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 498 WRAP_CONTENT, WRAP_CONTENT, 499 st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG, 500 WindowManager.LayoutParams.FLAG_DITHER 501 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 502 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 503 st.decorView.mDefaultOpacity); 504 505 lp.gravity = st.gravity; 506 lp.windowAnimations = st.windowAnimations; 507 508 wm.addView(st.decorView, lp); 509 // Log.v(TAG, "Adding main menu to window manager."); 510 } 511 512 @Override 513 public final void closePanel(int featureId) { 514 if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && 515 mActionBar.isOverflowReserved()) { 516 mActionBar.hideOverflowMenu(); 517 } else if (featureId == FEATURE_CONTEXT_MENU) { 518 closeContextMenu(); 519 } else { 520 closePanel(getPanelState(featureId, true), true); 521 } 522 } 523 524 /** 525 * Closes the given panel. 526 * 527 * @param st The panel to be closed. 528 * @param doCallback Whether to notify the callback that the panel was 529 * closed. If the panel is in the process of re-opening or 530 * opening another panel (e.g., menu opening a sub menu), the 531 * callback should not happen and this variable should be false. 532 * In addition, this method internally will only perform the 533 * callback if the panel is open. 534 */ 535 public final void closePanel(PanelFeatureState st, boolean doCallback) { 536 // System.out.println("Close panel: isOpen=" + st.isOpen); 537 final ViewManager wm = getWindowManager(); 538 if ((wm != null) && st.isOpen) { 539 if (st.decorView != null) { 540 wm.removeView(st.decorView); 541 // Log.v(TAG, "Removing main menu from window manager."); 542 } 543 544 if (doCallback) { 545 callOnPanelClosed(st.featureId, st, null); 546 } 547 } else if (st.featureId == FEATURE_OPTIONS_PANEL && doCallback && 548 mActionBar != null) { 549 checkCloseActionMenu(st.menu); 550 } 551 st.isPrepared = false; 552 st.isHandled = false; 553 st.isOpen = false; 554 555 // This view is no longer shown, so null it out 556 st.shownPanelView = null; 557 558 if (st.isInExpandedMode) { 559 // Next time the menu opens, it should not be in expanded mode, so 560 // force a refresh of the decor 561 st.refreshDecorView = true; 562 st.isInExpandedMode = false; 563 } 564 565 if (mPreparedPanel == st) { 566 mPreparedPanel = null; 567 mPanelChordingKey = 0; 568 } 569 } 570 571 private void checkCloseActionMenu(Menu menu) { 572 if (mClosingActionMenu) { 573 return; 574 } 575 576 boolean closed = false; 577 mClosingActionMenu = true; 578 if (mActionBar.isOverflowMenuOpen() && mActionBar.hideOverflowMenu()) { 579 closed = true; 580 } 581 if (mActionButtonPopup != null) { 582 mActionButtonPopup.dismiss(); 583 closed = true; 584 } 585 Callback cb = getCallback(); 586 if (cb != null && closed) { 587 cb.onPanelClosed(FEATURE_ACTION_BAR, menu); 588 } 589 mClosingActionMenu = false; 590 } 591 592 @Override 593 public final void togglePanel(int featureId, KeyEvent event) { 594 PanelFeatureState st = getPanelState(featureId, true); 595 if (st.isOpen) { 596 closePanel(st, true); 597 } else { 598 openPanel(st, event); 599 } 600 } 601 602 @Override 603 public void invalidatePanelMenu(int featureId) { 604 PanelFeatureState st = getPanelState(featureId, true); 605 if (st.menu != null) { 606 st.menu.clear(); 607 } 608 st.refreshMenuContent = true; 609 st.refreshDecorView = true; 610 611 // Prepare the options panel if we have an action bar 612 if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL) 613 && mActionBar != null) { 614 st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false); 615 if (st != null) { 616 st.isPrepared = false; 617 preparePanel(st, null); 618 } 619 } 620 } 621 622 /** 623 * Called when the panel key is pushed down. 624 * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}. 625 * @param event The key event. 626 * @return Whether the key was handled. 627 */ 628 public final boolean onKeyDownPanel(int featureId, KeyEvent event) { 629 final int keyCode = event.getKeyCode(); 630 631 if (event.getRepeatCount() == 0) { 632 // The panel key was pushed, so set the chording key 633 mPanelChordingKey = keyCode; 634 mPanelMayLongPress = false; 635 636 PanelFeatureState st = getPanelState(featureId, true); 637 if (!st.isOpen) { 638 if (getContext().getResources().getConfiguration().keyboard 639 == Configuration.KEYBOARD_NOKEYS) { 640 mPanelMayLongPress = true; 641 } 642 return preparePanel(st, event); 643 } 644 } else if (mPanelMayLongPress && mPanelChordingKey == keyCode 645 && (event.getFlags()&KeyEvent.FLAG_LONG_PRESS) != 0) { 646 // We have had a long press while in a state where this 647 // should be executed... do it! 648 mPanelChordingKey = 0; 649 mPanelMayLongPress = false; 650 } 651 652 return false; 653 } 654 655 /** 656 * Called when the panel key is released. 657 * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}. 658 * @param event The key event. 659 */ 660 public final void onKeyUpPanel(int featureId, KeyEvent event) { 661 // The panel key was released, so clear the chording key 662 if (mPanelChordingKey != 0) { 663 mPanelChordingKey = 0; 664 mPanelMayLongPress = false; 665 666 if (event.isCanceled()) { 667 return; 668 } 669 670 boolean playSoundEffect = false; 671 final PanelFeatureState st = getPanelState(featureId, true); 672 if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && 673 mActionBar.isOverflowReserved()) { 674 if (!mActionBar.isOverflowMenuShowing()) { 675 final Callback cb = getCallback(); 676 if (cb != null && 677 cb.onPreparePanel(featureId, st.createdPanelView, st.menu)) { 678 playSoundEffect = mActionBar.showOverflowMenu(); 679 } 680 } else { 681 playSoundEffect = mActionBar.hideOverflowMenu(); 682 } 683 } else { 684 if (st.isOpen || st.isHandled) { 685 686 // Play the sound effect if the user closed an open menu (and not if 687 // they just released a menu shortcut) 688 playSoundEffect = st.isOpen; 689 690 // Close menu 691 closePanel(st, true); 692 693 } else if (st.isPrepared) { 694 695 // Write 'menu opened' to event log 696 EventLog.writeEvent(50001, 0); 697 698 // Show menu 699 openPanel(st, event); 700 701 playSoundEffect = true; 702 } 703 } 704 705 if (playSoundEffect) { 706 AudioManager audioManager = (AudioManager) getContext().getSystemService( 707 Context.AUDIO_SERVICE); 708 if (audioManager != null) { 709 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); 710 } else { 711 Log.w(TAG, "Couldn't get audio manager"); 712 } 713 } 714 } 715 } 716 717 @Override 718 public final void closeAllPanels() { 719 final ViewManager wm = getWindowManager(); 720 if (wm == null) { 721 return; 722 } 723 724 final PanelFeatureState[] panels = mPanels; 725 final int N = panels != null ? panels.length : 0; 726 for (int i = 0; i < N; i++) { 727 final PanelFeatureState panel = panels[i]; 728 if (panel != null) { 729 closePanel(panel, true); 730 } 731 } 732 733 closeContextMenu(); 734 } 735 736 /** 737 * Closes the context menu. This notifies the menu logic of the close, along 738 * with dismissing it from the UI. 739 */ 740 private synchronized void closeContextMenu() { 741 if (mContextMenu != null) { 742 mContextMenu.close(); 743 dismissContextMenu(); 744 } 745 } 746 747 /** 748 * Dismisses just the context menu UI. To close the context menu, use 749 * {@link #closeContextMenu()}. 750 */ 751 private synchronized void dismissContextMenu() { 752 mContextMenu = null; 753 754 if (mContextMenuHelper != null) { 755 mContextMenuHelper.dismiss(); 756 mContextMenuHelper = null; 757 } 758 } 759 760 @Override 761 public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) { 762 return performPanelShortcut(getPanelState(featureId, true), keyCode, event, flags); 763 } 764 765 private boolean performPanelShortcut(PanelFeatureState st, int keyCode, KeyEvent event, 766 int flags) { 767 if (event.isSystem() || (st == null)) { 768 return false; 769 } 770 771 boolean handled = false; 772 773 // Only try to perform menu shortcuts if preparePanel returned true (possible false 774 // return value from application not wanting to show the menu). 775 if ((st.isPrepared || preparePanel(st, event)) && st.menu != null) { 776 // The menu is prepared now, perform the shortcut on it 777 handled = st.menu.performShortcut(keyCode, event, flags); 778 } 779 780 if (handled) { 781 // Mark as handled 782 st.isHandled = true; 783 784 if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0) { 785 closePanel(st, true); 786 } 787 } 788 789 return handled; 790 } 791 792 @Override 793 public boolean performPanelIdentifierAction(int featureId, int id, int flags) { 794 795 PanelFeatureState st = getPanelState(featureId, true); 796 if (!preparePanel(st, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU))) { 797 return false; 798 } 799 if (st.menu == null) { 800 return false; 801 } 802 803 boolean res = st.menu.performIdentifierAction(id, flags); 804 805 closePanel(st, true); 806 807 return res; 808 } 809 810 public PanelFeatureState findMenuPanel(Menu menu) { 811 final PanelFeatureState[] panels = mPanels; 812 final int N = panels != null ? panels.length : 0; 813 for (int i = 0; i < N; i++) { 814 final PanelFeatureState panel = panels[i]; 815 if (panel != null && panel.menu == menu) { 816 return panel; 817 } 818 } 819 return null; 820 } 821 822 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { 823 final Callback cb = getCallback(); 824 if (cb != null) { 825 final PanelFeatureState panel = findMenuPanel(menu.getRootMenu()); 826 if (panel != null) { 827 return cb.onMenuItemSelected(panel.featureId, item); 828 } 829 } 830 return false; 831 } 832 833 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 834 final PanelFeatureState panel = findMenuPanel(menu); 835 if (panel != null) { 836 // Close the panel and only do the callback if the menu is being 837 // closed 838 // completely, not if opening a sub menu 839 closePanel(panel, allMenusAreClosing); 840 } 841 } 842 843 public void onCloseSubMenu(SubMenuBuilder subMenu) { 844 final Menu parentMenu = subMenu.getRootMenu(); 845 final PanelFeatureState panel = findMenuPanel(parentMenu); 846 847 // Callback 848 if (panel != null) { 849 callOnPanelClosed(panel.featureId, panel, parentMenu); 850 closePanel(panel, true); 851 } 852 } 853 854 public boolean onSubMenuSelected(final SubMenuBuilder subMenu) { 855 if (!subMenu.hasVisibleItems()) { 856 return true; 857 } 858 859 final Menu parentMenu = subMenu.getRootMenu(); 860 final PanelFeatureState panel = findMenuPanel(parentMenu); 861 862 /* 863 * Use the panel open state to determine whether this is coming from an open panel 864 * or an action button. If it's an open panel we want to use MenuDialogHelper. 865 * If it's closed we want to grab the relevant view and create a popup anchored to it. 866 */ 867 if (panel.isOpen) { 868 // The window manager will give us a valid window token 869 new MenuDialogHelper(subMenu).show(null); 870 } else if (hasFeature(FEATURE_ACTION_BAR)) { 871 mActionButtonPopup = new ActionButtonSubmenu(getContext(), subMenu); 872 mActionButtonPopup.show(); 873 Callback cb = getCallback(); 874 if (cb != null) { 875 cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu); 876 } 877 } 878 879 return true; 880 } 881 882 public void onMenuModeChange(MenuBuilder menu) { 883 reopenMenu(true); 884 } 885 886 private void reopenMenu(boolean toggleMenuMode) { 887 if (mActionBar != null) { 888 final Callback cb = getCallback(); 889 if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) { 890 if (cb != null) { 891 final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); 892 if (cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) { 893 cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu); 894 mActionBar.openOverflowMenu(); 895 } 896 } 897 } else { 898 mActionBar.hideOverflowMenu(); 899 if (cb != null) { 900 final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); 901 cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu); 902 } 903 } 904 return; 905 } 906 907 PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); 908 909 // Save the future expanded mode state since closePanel will reset it 910 boolean newExpandedMode = toggleMenuMode ? !st.isInExpandedMode : st.isInExpandedMode; 911 912 st.refreshDecorView = true; 913 closePanel(st, false); 914 915 // Set the expanded mode state 916 st.isInExpandedMode = newExpandedMode; 917 918 openPanel(st, null); 919 } 920 921 /** 922 * Initializes the menu associated with the given panel feature state. You 923 * must at the very least set PanelFeatureState.menu to the Menu to be 924 * associated with the given panel state. The default implementation creates 925 * a new menu for the panel state. 926 * 927 * @param st The panel whose menu is being initialized. 928 * @return Whether the initialization was successful. 929 */ 930 protected boolean initializePanelMenu(final PanelFeatureState st) { 931 final MenuBuilder menu = new MenuBuilder(getContext()); 932 933 menu.setCallback(this); 934 st.setMenu(menu); 935 936 return true; 937 } 938 939 /** 940 * Perform initial setup of a panel. This should at the very least set the 941 * style information in the PanelFeatureState and must set 942 * PanelFeatureState.decor to the panel's window decor view. 943 * 944 * @param st The panel being initialized. 945 */ 946 protected boolean initializePanelDecor(PanelFeatureState st) { 947 st.decorView = new DecorView(getContext(), st.featureId); 948 st.gravity = Gravity.CENTER | Gravity.BOTTOM; 949 st.setStyle(getContext()); 950 951 return true; 952 } 953 954 /** 955 * Initializes the panel associated with the panel feature state. You must 956 * at the very least set PanelFeatureState.panel to the View implementing 957 * its contents. The default implementation gets the panel from the menu. 958 * 959 * @param st The panel state being initialized. 960 * @return Whether the initialization was successful. 961 */ 962 protected boolean initializePanelContent(PanelFeatureState st) { 963 964 if (st.createdPanelView != null) { 965 st.shownPanelView = st.createdPanelView; 966 return true; 967 } 968 969 final MenuBuilder menu = (MenuBuilder)st.menu; 970 if (menu == null) { 971 return false; 972 } 973 974 st.shownPanelView = menu.getMenuView((st.isInExpandedMode) ? MenuBuilder.TYPE_EXPANDED 975 : MenuBuilder.TYPE_ICON, st.decorView); 976 977 if (st.shownPanelView != null) { 978 // Use the menu View's default animations if it has any 979 final int defaultAnimations = ((MenuView) st.shownPanelView).getWindowAnimations(); 980 if (defaultAnimations != 0) { 981 st.windowAnimations = defaultAnimations; 982 } 983 return true; 984 } else { 985 return false; 986 } 987 } 988 989 @Override 990 public boolean performContextMenuIdentifierAction(int id, int flags) { 991 return (mContextMenu != null) ? mContextMenu.performIdentifierAction(id, flags) : false; 992 } 993 994 @Override 995 public final void setBackgroundDrawable(Drawable drawable) { 996 if (drawable != mBackgroundDrawable || mBackgroundResource != 0) { 997 mBackgroundResource = 0; 998 mBackgroundDrawable = drawable; 999 if (mDecor != null) { 1000 mDecor.setWindowBackground(drawable); 1001 } 1002 } 1003 } 1004 1005 @Override 1006 public final void setFeatureDrawableResource(int featureId, int resId) { 1007 if (resId != 0) { 1008 DrawableFeatureState st = getDrawableState(featureId, true); 1009 if (st.resid != resId) { 1010 st.resid = resId; 1011 st.uri = null; 1012 st.local = getContext().getResources().getDrawable(resId); 1013 updateDrawable(featureId, st, false); 1014 } 1015 } else { 1016 setFeatureDrawable(featureId, null); 1017 } 1018 } 1019 1020 @Override 1021 public final void setFeatureDrawableUri(int featureId, Uri uri) { 1022 if (uri != null) { 1023 DrawableFeatureState st = getDrawableState(featureId, true); 1024 if (st.uri == null || !st.uri.equals(uri)) { 1025 st.resid = 0; 1026 st.uri = uri; 1027 st.local = loadImageURI(uri); 1028 updateDrawable(featureId, st, false); 1029 } 1030 } else { 1031 setFeatureDrawable(featureId, null); 1032 } 1033 } 1034 1035 @Override 1036 public final void setFeatureDrawable(int featureId, Drawable drawable) { 1037 DrawableFeatureState st = getDrawableState(featureId, true); 1038 st.resid = 0; 1039 st.uri = null; 1040 if (st.local != drawable) { 1041 st.local = drawable; 1042 updateDrawable(featureId, st, false); 1043 } 1044 } 1045 1046 @Override 1047 public void setFeatureDrawableAlpha(int featureId, int alpha) { 1048 DrawableFeatureState st = getDrawableState(featureId, true); 1049 if (st.alpha != alpha) { 1050 st.alpha = alpha; 1051 updateDrawable(featureId, st, false); 1052 } 1053 } 1054 1055 protected final void setFeatureDefaultDrawable(int featureId, Drawable drawable) { 1056 DrawableFeatureState st = getDrawableState(featureId, true); 1057 if (st.def != drawable) { 1058 st.def = drawable; 1059 updateDrawable(featureId, st, false); 1060 } 1061 } 1062 1063 @Override 1064 public final void setFeatureInt(int featureId, int value) { 1065 // XXX Should do more management (as with drawable features) to 1066 // deal with interactions between multiple window policies. 1067 updateInt(featureId, value, false); 1068 } 1069 1070 /** 1071 * Update the state of a drawable feature. This should be called, for every 1072 * drawable feature supported, as part of onActive(), to make sure that the 1073 * contents of a containing window is properly updated. 1074 * 1075 * @see #onActive 1076 * @param featureId The desired drawable feature to change. 1077 * @param fromActive Always true when called from onActive(). 1078 */ 1079 protected final void updateDrawable(int featureId, boolean fromActive) { 1080 final DrawableFeatureState st = getDrawableState(featureId, false); 1081 if (st != null) { 1082 updateDrawable(featureId, st, fromActive); 1083 } 1084 } 1085 1086 /** 1087 * Called when a Drawable feature changes, for the window to update its 1088 * graphics. 1089 * 1090 * @param featureId The feature being changed. 1091 * @param drawable The new Drawable to show, or null if none. 1092 * @param alpha The new alpha blending of the Drawable. 1093 */ 1094 protected void onDrawableChanged(int featureId, Drawable drawable, int alpha) { 1095 ImageView view; 1096 if (featureId == FEATURE_LEFT_ICON) { 1097 view = getLeftIconView(); 1098 } else if (featureId == FEATURE_RIGHT_ICON) { 1099 view = getRightIconView(); 1100 } else { 1101 return; 1102 } 1103 1104 if (drawable != null) { 1105 drawable.setAlpha(alpha); 1106 view.setImageDrawable(drawable); 1107 view.setVisibility(View.VISIBLE); 1108 } else { 1109 view.setVisibility(View.GONE); 1110 } 1111 } 1112 1113 /** 1114 * Called when an int feature changes, for the window to update its 1115 * graphics. 1116 * 1117 * @param featureId The feature being changed. 1118 * @param value The new integer value. 1119 */ 1120 protected void onIntChanged(int featureId, int value) { 1121 if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) { 1122 updateProgressBars(value); 1123 } else if (featureId == FEATURE_CUSTOM_TITLE) { 1124 FrameLayout titleContainer = (FrameLayout) findViewById(com.android.internal.R.id.title_container); 1125 if (titleContainer != null) { 1126 mLayoutInflater.inflate(value, titleContainer); 1127 } 1128 } 1129 } 1130 1131 /** 1132 * Updates the progress bars that are shown in the title bar. 1133 * 1134 * @param value Can be one of {@link Window#PROGRESS_VISIBILITY_ON}, 1135 * {@link Window#PROGRESS_VISIBILITY_OFF}, 1136 * {@link Window#PROGRESS_INDETERMINATE_ON}, 1137 * {@link Window#PROGRESS_INDETERMINATE_OFF}, or a value 1138 * starting at {@link Window#PROGRESS_START} through 1139 * {@link Window#PROGRESS_END} for setting the default 1140 * progress (if {@link Window#PROGRESS_END} is given, 1141 * the progress bar widgets in the title will be hidden after an 1142 * animation), a value between 1143 * {@link Window#PROGRESS_SECONDARY_START} - 1144 * {@link Window#PROGRESS_SECONDARY_END} for the 1145 * secondary progress (if 1146 * {@link Window#PROGRESS_SECONDARY_END} is given, the 1147 * progress bar widgets will still be shown with the secondary 1148 * progress bar will be completely filled in.) 1149 */ 1150 private void updateProgressBars(int value) { 1151 ProgressBar circularProgressBar = getCircularProgressBar(true); 1152 ProgressBar horizontalProgressBar = getHorizontalProgressBar(true); 1153 1154 final int features = getLocalFeatures(); 1155 if (value == PROGRESS_VISIBILITY_ON) { 1156 if ((features & (1 << FEATURE_PROGRESS)) != 0) { 1157 int level = horizontalProgressBar.getProgress(); 1158 int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ? 1159 View.VISIBLE : View.INVISIBLE; 1160 horizontalProgressBar.setVisibility(visibility); 1161 } 1162 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { 1163 circularProgressBar.setVisibility(View.VISIBLE); 1164 } 1165 } else if (value == PROGRESS_VISIBILITY_OFF) { 1166 if ((features & (1 << FEATURE_PROGRESS)) != 0) { 1167 horizontalProgressBar.setVisibility(View.GONE); 1168 } 1169 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { 1170 circularProgressBar.setVisibility(View.GONE); 1171 } 1172 } else if (value == PROGRESS_INDETERMINATE_ON) { 1173 horizontalProgressBar.setIndeterminate(true); 1174 } else if (value == PROGRESS_INDETERMINATE_OFF) { 1175 horizontalProgressBar.setIndeterminate(false); 1176 } else if (PROGRESS_START <= value && value <= PROGRESS_END) { 1177 // We want to set the progress value before testing for visibility 1178 // so that when the progress bar becomes visible again, it has the 1179 // correct level. 1180 horizontalProgressBar.setProgress(value - PROGRESS_START); 1181 1182 if (value < PROGRESS_END) { 1183 showProgressBars(horizontalProgressBar, circularProgressBar); 1184 } else { 1185 hideProgressBars(horizontalProgressBar, circularProgressBar); 1186 } 1187 } else if (PROGRESS_SECONDARY_START <= value && value <= PROGRESS_SECONDARY_END) { 1188 horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START); 1189 1190 showProgressBars(horizontalProgressBar, circularProgressBar); 1191 } 1192 1193 } 1194 1195 private void showProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) { 1196 final int features = getLocalFeatures(); 1197 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 && 1198 spinnyProgressBar.getVisibility() == View.INVISIBLE) { 1199 spinnyProgressBar.setVisibility(View.VISIBLE); 1200 } 1201 // Only show the progress bars if the primary progress is not complete 1202 if ((features & (1 << FEATURE_PROGRESS)) != 0 && 1203 horizontalProgressBar.getProgress() < 10000) { 1204 horizontalProgressBar.setVisibility(View.VISIBLE); 1205 } 1206 } 1207 1208 private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) { 1209 final int features = getLocalFeatures(); 1210 Animation anim = AnimationUtils.loadAnimation(getContext(), com.android.internal.R.anim.fade_out); 1211 anim.setDuration(1000); 1212 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 && 1213 spinnyProgressBar.getVisibility() == View.VISIBLE) { 1214 spinnyProgressBar.startAnimation(anim); 1215 spinnyProgressBar.setVisibility(View.INVISIBLE); 1216 } 1217 if ((features & (1 << FEATURE_PROGRESS)) != 0 && 1218 horizontalProgressBar.getVisibility() == View.VISIBLE) { 1219 horizontalProgressBar.startAnimation(anim); 1220 horizontalProgressBar.setVisibility(View.INVISIBLE); 1221 } 1222 } 1223 1224 /** 1225 * Request that key events come to this activity. Use this if your activity 1226 * has no views with focus, but the activity still wants a chance to process 1227 * key events. 1228 */ 1229 @Override 1230 public void takeKeyEvents(boolean get) { 1231 mDecor.setFocusable(get); 1232 } 1233 1234 @Override 1235 public boolean superDispatchKeyEvent(KeyEvent event) { 1236 return mDecor.superDispatchKeyEvent(event); 1237 } 1238 1239 @Override 1240 public boolean superDispatchKeyShortcutEvent(KeyEvent event) { 1241 return mDecor.superDispatchKeyShortcutEvent(event); 1242 } 1243 1244 @Override 1245 public boolean superDispatchTouchEvent(MotionEvent event) { 1246 return mDecor.superDispatchTouchEvent(event); 1247 } 1248 1249 @Override 1250 public boolean superDispatchTrackballEvent(MotionEvent event) { 1251 return mDecor.superDispatchTrackballEvent(event); 1252 } 1253 1254 /** 1255 * A key was pressed down and not handled by anything else in the window. 1256 * 1257 * @see #onKeyUp 1258 * @see android.view.KeyEvent 1259 */ 1260 protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) { 1261 /* **************************************************************************** 1262 * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES. 1263 * 1264 * If your key handling must happen before the app gets a crack at the event, 1265 * it goes in PhoneWindowManager. 1266 * 1267 * If your key handling should happen in all windows, and does not depend on 1268 * the state of the current application, other than that the current 1269 * application can override the behavior by handling the event itself, it 1270 * should go in PhoneFallbackEventHandler. 1271 * 1272 * Only if your handling depends on the window, and the fact that it has 1273 * a DecorView, should it go here. 1274 * ****************************************************************************/ 1275 1276 final KeyEvent.DispatcherState dispatcher = 1277 mDecor != null ? mDecor.getKeyDispatcherState() : null; 1278 //Log.i(TAG, "Key down: repeat=" + event.getRepeatCount() 1279 // + " flags=0x" + Integer.toHexString(event.getFlags())); 1280 1281 switch (keyCode) { 1282 case KeyEvent.KEYCODE_VOLUME_UP: 1283 case KeyEvent.KEYCODE_VOLUME_DOWN: 1284 case KeyEvent.KEYCODE_VOLUME_MUTE: { 1285 // Similar code is in PhoneFallbackEventHandler in case the window 1286 // doesn't have one of these. In this case, we execute it here and 1287 // eat the event instead, because we have mVolumeControlStreamType 1288 // and they don't. 1289 getAudioManager().handleKeyDown(keyCode, mVolumeControlStreamType); 1290 return true; 1291 } 1292 1293 case KeyEvent.KEYCODE_MENU: { 1294 onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event); 1295 return true; 1296 } 1297 1298 case KeyEvent.KEYCODE_BACK: { 1299 if (event.getRepeatCount() > 0) break; 1300 if (featureId < 0) break; 1301 // Currently don't do anything with long press. 1302 dispatcher.startTracking(event, this); 1303 return true; 1304 } 1305 1306 } 1307 1308 return false; 1309 } 1310 1311 private KeyguardManager getKeyguardManager() { 1312 if (mKeyguardManager == null) { 1313 mKeyguardManager = (KeyguardManager) getContext().getSystemService( 1314 Context.KEYGUARD_SERVICE); 1315 } 1316 return mKeyguardManager; 1317 } 1318 1319 AudioManager getAudioManager() { 1320 if (mAudioManager == null) { 1321 mAudioManager = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE); 1322 } 1323 return mAudioManager; 1324 } 1325 1326 /** 1327 * A key was released and not handled by anything else in the window. 1328 * 1329 * @see #onKeyDown 1330 * @see android.view.KeyEvent 1331 */ 1332 protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) { 1333 final KeyEvent.DispatcherState dispatcher = 1334 mDecor != null ? mDecor.getKeyDispatcherState() : null; 1335 if (dispatcher != null) { 1336 dispatcher.handleUpEvent(event); 1337 } 1338 //Log.i(TAG, "Key up: repeat=" + event.getRepeatCount() 1339 // + " flags=0x" + Integer.toHexString(event.getFlags())); 1340 1341 switch (keyCode) { 1342 case KeyEvent.KEYCODE_VOLUME_UP: 1343 case KeyEvent.KEYCODE_VOLUME_DOWN: 1344 case KeyEvent.KEYCODE_VOLUME_MUTE: { 1345 // Similar code is in PhoneFallbackEventHandler in case the window 1346 // doesn't have one of these. In this case, we execute it here and 1347 // eat the event instead, because we have mVolumeControlStreamType 1348 // and they don't. 1349 getAudioManager().handleKeyUp(keyCode, mVolumeControlStreamType); 1350 return true; 1351 } 1352 1353 case KeyEvent.KEYCODE_MENU: { 1354 onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId, 1355 event); 1356 return true; 1357 } 1358 1359 case KeyEvent.KEYCODE_BACK: { 1360 if (featureId < 0) break; 1361 if (event.isTracking() && !event.isCanceled()) { 1362 if (featureId == FEATURE_OPTIONS_PANEL) { 1363 PanelFeatureState st = getPanelState(featureId, false); 1364 if (st != null && st.isInExpandedMode) { 1365 // If the user is in an expanded menu and hits back, it 1366 // should go back to the icon menu 1367 reopenMenu(true); 1368 return true; 1369 } 1370 } 1371 closePanel(featureId); 1372 return true; 1373 } 1374 break; 1375 } 1376 1377 case KeyEvent.KEYCODE_SEARCH: { 1378 /* 1379 * Do this in onKeyUp since the Search key is also used for 1380 * chording quick launch shortcuts. 1381 */ 1382 if (getKeyguardManager().inKeyguardRestrictedInputMode()) { 1383 break; 1384 } 1385 if (event.isTracking() && !event.isCanceled()) { 1386 launchDefaultSearch(); 1387 } 1388 return true; 1389 } 1390 } 1391 1392 return false; 1393 } 1394 1395 @Override 1396 protected void onActive() { 1397 } 1398 1399 @Override 1400 public final View getDecorView() { 1401 if (mDecor == null) { 1402 installDecor(); 1403 } 1404 return mDecor; 1405 } 1406 1407 @Override 1408 public final View peekDecorView() { 1409 return mDecor; 1410 } 1411 1412 static private final String FOCUSED_ID_TAG = "android:focusedViewId"; 1413 static private final String VIEWS_TAG = "android:views"; 1414 static private final String PANELS_TAG = "android:Panels"; 1415 static private final String ACTION_BAR_TAG = "android:ActionBar"; 1416 1417 /** {@inheritDoc} */ 1418 @Override 1419 public Bundle saveHierarchyState() { 1420 Bundle outState = new Bundle(); 1421 if (mContentParent == null) { 1422 return outState; 1423 } 1424 1425 SparseArray<Parcelable> states = new SparseArray<Parcelable>(); 1426 mContentParent.saveHierarchyState(states); 1427 outState.putSparseParcelableArray(VIEWS_TAG, states); 1428 1429 // save the focused view id 1430 View focusedView = mContentParent.findFocus(); 1431 if (focusedView != null) { 1432 if (focusedView.getId() != View.NO_ID) { 1433 outState.putInt(FOCUSED_ID_TAG, focusedView.getId()); 1434 } else { 1435 if (Config.LOGD) { 1436 Log.d(TAG, "couldn't save which view has focus because the focused view " 1437 + focusedView + " has no id."); 1438 } 1439 } 1440 } 1441 1442 // save the panels 1443 SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>(); 1444 savePanelState(panelStates); 1445 if (panelStates.size() > 0) { 1446 outState.putSparseParcelableArray(PANELS_TAG, panelStates); 1447 } 1448 1449 if (mActionBar != null) { 1450 outState.putBoolean(ACTION_BAR_TAG, mActionBar.isOverflowMenuShowing()); 1451 } 1452 1453 return outState; 1454 } 1455 1456 /** {@inheritDoc} */ 1457 @Override 1458 public void restoreHierarchyState(Bundle savedInstanceState) { 1459 if (mContentParent == null) { 1460 return; 1461 } 1462 1463 SparseArray<Parcelable> savedStates 1464 = savedInstanceState.getSparseParcelableArray(VIEWS_TAG); 1465 if (savedStates != null) { 1466 mContentParent.restoreHierarchyState(savedStates); 1467 } 1468 1469 // restore the focused view 1470 int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID); 1471 if (focusedViewId != View.NO_ID) { 1472 View needsFocus = mContentParent.findViewById(focusedViewId); 1473 if (needsFocus != null) { 1474 needsFocus.requestFocus(); 1475 } else { 1476 Log.w(TAG, 1477 "Previously focused view reported id " + focusedViewId 1478 + " during save, but can't be found during restore."); 1479 } 1480 } 1481 1482 // restore the panels 1483 SparseArray<Parcelable> panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG); 1484 if (panelStates != null) { 1485 restorePanelState(panelStates); 1486 } 1487 1488 if (mActionBar != null && savedInstanceState.getBoolean(ACTION_BAR_TAG)) { 1489 mActionBar.postShowOverflowMenu(); 1490 } 1491 } 1492 1493 /** 1494 * Invoked when the panels should freeze their state. 1495 * 1496 * @param icicles Save state into this. This is usually indexed by the 1497 * featureId. This will be given to {@link #restorePanelState} in the 1498 * future. 1499 */ 1500 private void savePanelState(SparseArray<Parcelable> icicles) { 1501 PanelFeatureState[] panels = mPanels; 1502 if (panels == null) { 1503 return; 1504 } 1505 1506 for (int curFeatureId = panels.length - 1; curFeatureId >= 0; curFeatureId--) { 1507 if (panels[curFeatureId] != null) { 1508 icicles.put(curFeatureId, panels[curFeatureId].onSaveInstanceState()); 1509 } 1510 } 1511 } 1512 1513 /** 1514 * Invoked when the panels should thaw their state from a previously frozen state. 1515 * 1516 * @param icicles The state saved by {@link #savePanelState} that needs to be thawed. 1517 */ 1518 private void restorePanelState(SparseArray<Parcelable> icicles) { 1519 PanelFeatureState st; 1520 for (int curFeatureId = icicles.size() - 1; curFeatureId >= 0; curFeatureId--) { 1521 st = getPanelState(curFeatureId, false /* required */); 1522 if (st == null) { 1523 // The panel must not have been required, and is currently not around, skip it 1524 continue; 1525 } 1526 1527 st.onRestoreInstanceState(icicles.get(curFeatureId)); 1528 } 1529 1530 /* 1531 * Implementation note: call openPanelsAfterRestore later to actually open the 1532 * restored panels. 1533 */ 1534 } 1535 1536 /** 1537 * Opens the panels that have had their state restored. This should be 1538 * called sometime after {@link #restorePanelState} when it is safe to add 1539 * to the window manager. 1540 */ 1541 private void openPanelsAfterRestore() { 1542 PanelFeatureState[] panels = mPanels; 1543 1544 if (panels == null) { 1545 return; 1546 } 1547 1548 PanelFeatureState st; 1549 for (int i = panels.length - 1; i >= 0; i--) { 1550 st = panels[i]; 1551 // We restore the panel if it was last open; we skip it if it 1552 // now is open, to avoid a race condition if the user immediately 1553 // opens it when we are resuming. 1554 if ((st != null) && !st.isOpen && st.wasLastOpen) { 1555 st.isInExpandedMode = st.wasLastExpanded; 1556 openPanel(st, null); 1557 } 1558 } 1559 } 1560 1561 private final class DecorView extends FrameLayout implements RootViewSurfaceTaker { 1562 /* package */int mDefaultOpacity = PixelFormat.OPAQUE; 1563 1564 /** The feature ID of the panel, or -1 if this is the application's DecorView */ 1565 private final int mFeatureId; 1566 1567 private final Rect mDrawingBounds = new Rect(); 1568 1569 private final Rect mBackgroundPadding = new Rect(); 1570 1571 private final Rect mFramePadding = new Rect(); 1572 1573 private final Rect mFrameOffsets = new Rect(); 1574 1575 private boolean mChanging; 1576 1577 private Drawable mMenuBackground; 1578 private boolean mWatchingForMenu; 1579 private int mDownY; 1580 1581 private ActionMode mActionMode; 1582 private ActionBarContextView mActionModeView; 1583 private PopupWindow mActionModePopup; 1584 1585 public DecorView(Context context, int featureId) { 1586 super(context); 1587 mFeatureId = featureId; 1588 } 1589 1590 @Override 1591 public boolean dispatchKeyEvent(KeyEvent event) { 1592 final int keyCode = event.getKeyCode(); 1593 final int action = event.getAction(); 1594 final boolean isDown = action == KeyEvent.ACTION_DOWN; 1595 1596 if (isDown && (event.getRepeatCount() == 0)) { 1597 // First handle chording of panel key: if a panel key is held 1598 // but not released, try to execute a shortcut in it. 1599 if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) { 1600 // Perform the shortcut (mPreparedPanel can be null since 1601 // global shortcuts (such as search) don't rely on a 1602 // prepared panel or menu). 1603 boolean handled = performPanelShortcut(mPreparedPanel, keyCode, event, 1604 Menu.FLAG_PERFORM_NO_CLOSE); 1605 1606 if (!handled) { 1607 /* 1608 * If not handled, then pass it to the view hierarchy 1609 * and anyone else that may be interested. 1610 */ 1611 handled = dispatchKeyShortcutEvent(event); 1612 1613 if (handled && mPreparedPanel != null) { 1614 mPreparedPanel.isHandled = true; 1615 } 1616 } 1617 1618 if (handled) { 1619 return true; 1620 } 1621 } 1622 1623 // If a panel is open, perform a shortcut on it without the 1624 // chorded panel key 1625 if ((mPreparedPanel != null) && mPreparedPanel.isOpen) { 1626 if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) { 1627 return true; 1628 } 1629 } 1630 } 1631 1632 // Back cancels action modes first. 1633 if (mActionMode != null && keyCode == KeyEvent.KEYCODE_BACK) { 1634 if (action == KeyEvent.ACTION_UP) { 1635 mActionMode.finish(); 1636 } 1637 return true; 1638 } 1639 1640 final Callback cb = getCallback(); 1641 final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) 1642 : super.dispatchKeyEvent(event); 1643 if (handled) { 1644 return true; 1645 } 1646 return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event) 1647 : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event); 1648 } 1649 1650 @Override 1651 public boolean dispatchKeyShortcutEvent(KeyEvent ev) { 1652 final Callback cb = getCallback(); 1653 return cb != null && mFeatureId < 0 ? cb.dispatchKeyShortcutEvent(ev) : super 1654 .dispatchKeyShortcutEvent(ev); 1655 } 1656 1657 @Override 1658 public boolean dispatchTouchEvent(MotionEvent ev) { 1659 final Callback cb = getCallback(); 1660 return cb != null && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super 1661 .dispatchTouchEvent(ev); 1662 } 1663 1664 @Override 1665 public boolean dispatchTrackballEvent(MotionEvent ev) { 1666 final Callback cb = getCallback(); 1667 return cb != null && mFeatureId < 0 ? cb.dispatchTrackballEvent(ev) : super 1668 .dispatchTrackballEvent(ev); 1669 } 1670 1671 public boolean superDispatchKeyEvent(KeyEvent event) { 1672 return super.dispatchKeyEvent(event); 1673 } 1674 1675 public boolean superDispatchKeyShortcutEvent(KeyEvent event) { 1676 return super.dispatchKeyShortcutEvent(event); 1677 } 1678 1679 public boolean superDispatchTouchEvent(MotionEvent event) { 1680 return super.dispatchTouchEvent(event); 1681 } 1682 1683 public boolean superDispatchTrackballEvent(MotionEvent event) { 1684 return super.dispatchTrackballEvent(event); 1685 } 1686 1687 @Override 1688 public boolean onTouchEvent(MotionEvent event) { 1689 return onInterceptTouchEvent(event); 1690 } 1691 1692 private boolean isOutOfBounds(int x, int y) { 1693 return x < -5 || y < -5 || x > (getWidth() + 5) 1694 || y > (getHeight() + 5); 1695 } 1696 1697 @Override 1698 public boolean onInterceptTouchEvent(MotionEvent event) { 1699 int action = event.getAction(); 1700 if (mFeatureId >= 0) { 1701 if (action == MotionEvent.ACTION_DOWN) { 1702 int x = (int)event.getX(); 1703 int y = (int)event.getY(); 1704 if (isOutOfBounds(x, y)) { 1705 closePanel(mFeatureId); 1706 return true; 1707 } 1708 } 1709 } 1710 1711 if (!SWEEP_OPEN_MENU) { 1712 return false; 1713 } 1714 1715 if (mFeatureId >= 0) { 1716 if (action == MotionEvent.ACTION_DOWN) { 1717 Log.i(TAG, "Watchiing!"); 1718 mWatchingForMenu = true; 1719 mDownY = (int) event.getY(); 1720 return false; 1721 } 1722 1723 if (!mWatchingForMenu) { 1724 return false; 1725 } 1726 1727 int y = (int)event.getY(); 1728 if (action == MotionEvent.ACTION_MOVE) { 1729 if (y > (mDownY+30)) { 1730 Log.i(TAG, "Closing!"); 1731 closePanel(mFeatureId); 1732 mWatchingForMenu = false; 1733 return true; 1734 } 1735 } else if (action == MotionEvent.ACTION_UP) { 1736 mWatchingForMenu = false; 1737 } 1738 1739 return false; 1740 } 1741 1742 //Log.i(TAG, "Intercept: action=" + action + " y=" + event.getY() 1743 // + " (in " + getHeight() + ")"); 1744 1745 if (action == MotionEvent.ACTION_DOWN) { 1746 int y = (int)event.getY(); 1747 if (y >= (getHeight()-5) && !hasChildren()) { 1748 Log.i(TAG, "Watchiing!"); 1749 mWatchingForMenu = true; 1750 } 1751 return false; 1752 } 1753 1754 if (!mWatchingForMenu) { 1755 return false; 1756 } 1757 1758 int y = (int)event.getY(); 1759 if (action == MotionEvent.ACTION_MOVE) { 1760 if (y < (getHeight()-30)) { 1761 Log.i(TAG, "Opening!"); 1762 openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent( 1763 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU)); 1764 mWatchingForMenu = false; 1765 return true; 1766 } 1767 } else if (action == MotionEvent.ACTION_UP) { 1768 mWatchingForMenu = false; 1769 } 1770 1771 return false; 1772 } 1773 1774 @Override 1775 public void sendAccessibilityEvent(int eventType) { 1776 if (!AccessibilityManager.getInstance(mContext).isEnabled()) { 1777 return; 1778 } 1779 1780 // if we are showing a feature that should be announced and one child 1781 // make this child the event source since this is the feature itself 1782 // otherwise the callback will take over and announce its client 1783 if ((mFeatureId == FEATURE_OPTIONS_PANEL || 1784 mFeatureId == FEATURE_CONTEXT_MENU || 1785 mFeatureId == FEATURE_PROGRESS || 1786 mFeatureId == FEATURE_INDETERMINATE_PROGRESS) 1787 && getChildCount() == 1) { 1788 getChildAt(0).sendAccessibilityEvent(eventType); 1789 } else { 1790 super.sendAccessibilityEvent(eventType); 1791 } 1792 } 1793 1794 @Override 1795 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 1796 final Callback cb = getCallback(); 1797 if (cb != null) { 1798 if (cb.dispatchPopulateAccessibilityEvent(event)) { 1799 return true; 1800 } 1801 } 1802 return super.dispatchPopulateAccessibilityEvent(event); 1803 } 1804 1805 @Override 1806 protected boolean setFrame(int l, int t, int r, int b) { 1807 boolean changed = super.setFrame(l, t, r, b); 1808 if (changed) { 1809 final Rect drawingBounds = mDrawingBounds; 1810 getDrawingRect(drawingBounds); 1811 1812 Drawable fg = getForeground(); 1813 if (fg != null) { 1814 final Rect frameOffsets = mFrameOffsets; 1815 drawingBounds.left += frameOffsets.left; 1816 drawingBounds.top += frameOffsets.top; 1817 drawingBounds.right -= frameOffsets.right; 1818 drawingBounds.bottom -= frameOffsets.bottom; 1819 fg.setBounds(drawingBounds); 1820 final Rect framePadding = mFramePadding; 1821 drawingBounds.left += framePadding.left - frameOffsets.left; 1822 drawingBounds.top += framePadding.top - frameOffsets.top; 1823 drawingBounds.right -= framePadding.right - frameOffsets.right; 1824 drawingBounds.bottom -= framePadding.bottom - frameOffsets.bottom; 1825 } 1826 1827 Drawable bg = getBackground(); 1828 if (bg != null) { 1829 bg.setBounds(drawingBounds); 1830 } 1831 1832 if (SWEEP_OPEN_MENU) { 1833 if (mMenuBackground == null && mFeatureId < 0 1834 && getAttributes().height 1835 == WindowManager.LayoutParams.MATCH_PARENT) { 1836 mMenuBackground = getContext().getResources().getDrawable( 1837 com.android.internal.R.drawable.menu_background); 1838 } 1839 if (mMenuBackground != null) { 1840 mMenuBackground.setBounds(drawingBounds.left, 1841 drawingBounds.bottom-6, drawingBounds.right, 1842 drawingBounds.bottom+20); 1843 } 1844 } 1845 } 1846 return changed; 1847 } 1848 1849 @Override 1850 public void draw(Canvas canvas) { 1851 super.draw(canvas); 1852 1853 if (mMenuBackground != null) { 1854 mMenuBackground.draw(canvas); 1855 } 1856 } 1857 1858 1859 @Override 1860 public boolean showContextMenuForChild(View originalView) { 1861 // Reuse the context menu builder 1862 if (mContextMenu == null) { 1863 mContextMenu = new ContextMenuBuilder(getContext()); 1864 mContextMenu.setCallback(mContextMenuCallback); 1865 } else { 1866 mContextMenu.clearAll(); 1867 } 1868 1869 mContextMenuHelper = mContextMenu.show(originalView, originalView.getWindowToken()); 1870 return mContextMenuHelper != null; 1871 } 1872 1873 @Override 1874 public ActionMode startActionModeForChild(View originalView, 1875 ActionMode.Callback callback) { 1876 // originalView can be used here to be sure that we don't obscure 1877 // relevant content with the context mode UI. 1878 return startActionMode(callback); 1879 } 1880 1881 @Override 1882 public ActionMode startActionMode(ActionMode.Callback callback) { 1883 if (mActionMode != null) { 1884 mActionMode.finish(); 1885 } 1886 1887 final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback); 1888 ActionMode mode = null; 1889 try { 1890 mode = getCallback().onWindowStartingActionMode(wrappedCallback); 1891 } catch (AbstractMethodError ame) { 1892 // Older apps might not implement this callback method. 1893 } 1894 if (mode != null) { 1895 mActionMode = mode; 1896 } else { 1897 if (mActionModeView == null) { 1898 if (hasFeature(FEATURE_ACTION_MODE_OVERLAY)) { 1899 mActionModeView = new ActionBarContextView(mContext); 1900 mActionModePopup = new PopupWindow(mContext, null, 1901 com.android.internal.R.attr.actionModePopupWindowStyle); 1902 mActionModePopup.setLayoutInScreenEnabled(true); 1903 mActionModePopup.setClippingEnabled(false); 1904 mActionModePopup.setContentView(mActionModeView); 1905 mActionModePopup.setWidth(MATCH_PARENT); 1906 1907 TypedValue heightValue = new TypedValue(); 1908 mContext.getTheme().resolveAttribute( 1909 com.android.internal.R.attr.actionBarSize, heightValue, false); 1910 final int height = TypedValue.complexToDimensionPixelSize(heightValue.data, 1911 mContext.getResources().getDisplayMetrics()); 1912 mActionModePopup.setHeight(height); 1913 } else { 1914 ViewStub stub = (ViewStub) findViewById( 1915 com.android.internal.R.id.action_mode_bar_stub); 1916 if (stub != null) { 1917 mActionModeView = (ActionBarContextView) stub.inflate(); 1918 } 1919 } 1920 } 1921 1922 if (mActionModeView != null) { 1923 mode = new StandaloneActionMode(getContext(), mActionModeView, wrappedCallback); 1924 if (callback.onCreateActionMode(mode, mode.getMenu())) { 1925 mode.invalidate(); 1926 mActionModeView.initForMode(mode); 1927 mActionModeView.setVisibility(View.VISIBLE); 1928 mActionMode = mode; 1929 if (mActionModePopup != null) { 1930 mActionModePopup.showAtLocation(this, 1931 Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0); 1932 } 1933 } else { 1934 mActionMode = null; 1935 } 1936 } 1937 } 1938 if (mActionMode != null) { 1939 try { 1940 getCallback().onActionModeStarted(mActionMode); 1941 } catch (AbstractMethodError ame) { 1942 // Older apps might not implement this callback method. 1943 } 1944 } 1945 return mActionMode; 1946 } 1947 1948 public void startChanging() { 1949 mChanging = true; 1950 } 1951 1952 public void finishChanging() { 1953 mChanging = false; 1954 drawableChanged(); 1955 } 1956 1957 public void setWindowBackground(Drawable drawable) { 1958 if (getBackground() != drawable) { 1959 setBackgroundDrawable(drawable); 1960 if (drawable != null) { 1961 drawable.getPadding(mBackgroundPadding); 1962 } else { 1963 mBackgroundPadding.setEmpty(); 1964 } 1965 drawableChanged(); 1966 } 1967 } 1968 1969 public void setWindowFrame(Drawable drawable) { 1970 if (getForeground() != drawable) { 1971 setForeground(drawable); 1972 if (drawable != null) { 1973 drawable.getPadding(mFramePadding); 1974 } else { 1975 mFramePadding.setEmpty(); 1976 } 1977 drawableChanged(); 1978 } 1979 } 1980 1981 @Override 1982 protected boolean fitSystemWindows(Rect insets) { 1983 mFrameOffsets.set(insets); 1984 if (getForeground() != null) { 1985 drawableChanged(); 1986 } 1987 return super.fitSystemWindows(insets); 1988 } 1989 1990 private void drawableChanged() { 1991 if (mChanging) { 1992 return; 1993 } 1994 1995 setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top 1996 + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right, 1997 mFramePadding.bottom + mBackgroundPadding.bottom); 1998 requestLayout(); 1999 invalidate(); 2000 2001 int opacity = PixelFormat.OPAQUE; 2002 2003 // Note: if there is no background, we will assume opaque. The 2004 // common case seems to be that an application sets there to be 2005 // no background so it can draw everything itself. For that, 2006 // we would like to assume OPAQUE and let the app force it to 2007 // the slower TRANSLUCENT mode if that is really what it wants. 2008 Drawable bg = getBackground(); 2009 Drawable fg = getForeground(); 2010 if (bg != null) { 2011 if (fg == null) { 2012 opacity = bg.getOpacity(); 2013 } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0 2014 && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) { 2015 // If the frame padding is zero, then we can be opaque 2016 // if either the frame -or- the background is opaque. 2017 int fop = fg.getOpacity(); 2018 int bop = bg.getOpacity(); 2019 if (Config.LOGV) 2020 Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop); 2021 if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) { 2022 opacity = PixelFormat.OPAQUE; 2023 } else if (fop == PixelFormat.UNKNOWN) { 2024 opacity = bop; 2025 } else if (bop == PixelFormat.UNKNOWN) { 2026 opacity = fop; 2027 } else { 2028 opacity = Drawable.resolveOpacity(fop, bop); 2029 } 2030 } else { 2031 // For now we have to assume translucent if there is a 2032 // frame with padding... there is no way to tell if the 2033 // frame and background together will draw all pixels. 2034 if (Config.LOGV) 2035 Log.v(TAG, "Padding: " + mFramePadding); 2036 opacity = PixelFormat.TRANSLUCENT; 2037 } 2038 } 2039 2040 if (Config.LOGV) 2041 Log.v(TAG, "Background: " + bg + ", Frame: " + fg); 2042 if (Config.LOGV) 2043 Log.v(TAG, "Selected default opacity: " + opacity); 2044 2045 mDefaultOpacity = opacity; 2046 if (mFeatureId < 0) { 2047 setDefaultWindowFormat(opacity); 2048 } 2049 } 2050 2051 @Override 2052 public void onWindowFocusChanged(boolean hasWindowFocus) { 2053 super.onWindowFocusChanged(hasWindowFocus); 2054 2055 mPanelMayLongPress = false; 2056 2057 // If the user is chording a menu shortcut, release the chord since 2058 // this window lost focus 2059 if (!hasWindowFocus && mPanelChordingKey != 0) { 2060 closePanel(FEATURE_OPTIONS_PANEL); 2061 } 2062 2063 final Callback cb = getCallback(); 2064 if (cb != null && mFeatureId < 0) { 2065 cb.onWindowFocusChanged(hasWindowFocus); 2066 } 2067 } 2068 2069 @Override 2070 protected void onAttachedToWindow() { 2071 super.onAttachedToWindow(); 2072 2073 final Callback cb = getCallback(); 2074 if (cb != null && mFeatureId < 0) { 2075 cb.onAttachedToWindow(); 2076 } 2077 2078 if (mFeatureId == -1) { 2079 /* 2080 * The main window has been attached, try to restore any panels 2081 * that may have been open before. This is called in cases where 2082 * an activity is being killed for configuration change and the 2083 * menu was open. When the activity is recreated, the menu 2084 * should be shown again. 2085 */ 2086 openPanelsAfterRestore(); 2087 } 2088 } 2089 2090 @Override 2091 protected void onDetachedFromWindow() { 2092 super.onDetachedFromWindow(); 2093 2094 final Callback cb = getCallback(); 2095 if (cb != null && mFeatureId < 0) { 2096 cb.onDetachedFromWindow(); 2097 } 2098 2099 if (mActionButtonPopup != null) { 2100 if (mActionButtonPopup.isShowing()) { 2101 mActionButtonPopup.dismiss(); 2102 } 2103 mActionButtonPopup = null; 2104 } 2105 } 2106 2107 @Override 2108 protected void onConfigurationChanged(Configuration newConfig) { 2109 if (mActionButtonPopup != null) { 2110 mActionButtonPopup.dismiss(); 2111 post(mActionButtonPopup); 2112 } 2113 } 2114 2115 @Override 2116 public void onCloseSystemDialogs(String reason) { 2117 if (mFeatureId >= 0) { 2118 closeAllPanels(); 2119 } 2120 } 2121 2122 public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface() { 2123 return mFeatureId < 0 ? mTakeSurfaceCallback : null; 2124 } 2125 2126 public InputQueue.Callback willYouTakeTheInputQueue() { 2127 return mFeatureId < 0 ? mTakeInputQueueCallback : null; 2128 } 2129 2130 public void setSurfaceType(int type) { 2131 PhoneWindow.this.setType(type); 2132 } 2133 2134 public void setSurfaceFormat(int format) { 2135 PhoneWindow.this.setFormat(format); 2136 } 2137 2138 public void setSurfaceKeepScreenOn(boolean keepOn) { 2139 if (keepOn) PhoneWindow.this.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 2140 else PhoneWindow.this.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 2141 } 2142 2143 /** 2144 * Clears out internal reference when the action mode is destroyed. 2145 */ 2146 private class ActionModeCallbackWrapper implements ActionMode.Callback { 2147 private ActionMode.Callback mWrapped; 2148 2149 public ActionModeCallbackWrapper(ActionMode.Callback wrapped) { 2150 mWrapped = wrapped; 2151 } 2152 2153 public boolean onCreateActionMode(ActionMode mode, Menu menu) { 2154 return mWrapped.onCreateActionMode(mode, menu); 2155 } 2156 2157 public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 2158 return mWrapped.onPrepareActionMode(mode, menu); 2159 } 2160 2161 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 2162 return mWrapped.onActionItemClicked(mode, item); 2163 } 2164 2165 public void onDestroyActionMode(ActionMode mode) { 2166 mWrapped.onDestroyActionMode(mode); 2167 if (mActionModePopup != null) { 2168 mActionModePopup.dismiss(); 2169 } else if (mActionModeView != null) { 2170 mActionModeView.setVisibility(GONE); 2171 } 2172 if (mActionModeView != null) { 2173 mActionModeView.removeAllViews(); 2174 } 2175 try { 2176 getCallback().onActionModeFinished(mActionMode); 2177 } catch (AbstractMethodError ame) { 2178 // Older apps might not implement this callback method. 2179 } 2180 mActionMode = null; 2181 } 2182 } 2183 } 2184 2185 protected DecorView generateDecor() { 2186 return new DecorView(getContext(), -1); 2187 } 2188 2189 protected void setFeatureFromAttrs(int featureId, TypedArray attrs, 2190 int drawableAttr, int alphaAttr) { 2191 Drawable d = attrs.getDrawable(drawableAttr); 2192 if (d != null) { 2193 requestFeature(featureId); 2194 setFeatureDefaultDrawable(featureId, d); 2195 } 2196 if ((getFeatures() & (1 << featureId)) != 0) { 2197 int alpha = attrs.getInt(alphaAttr, -1); 2198 if (alpha >= 0) { 2199 setFeatureDrawableAlpha(featureId, alpha); 2200 } 2201 } 2202 } 2203 2204 protected ViewGroup generateLayout(DecorView decor) { 2205 // Apply data from current theme. 2206 2207 TypedArray a = getWindowStyle(); 2208 2209 if (false) { 2210 System.out.println("From style:"); 2211 String s = "Attrs:"; 2212 for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) { 2213 s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "=" 2214 + a.getString(i); 2215 } 2216 System.out.println(s); 2217 } 2218 2219 mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false); 2220 int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR) 2221 & (~getForcedWindowFlags()); 2222 if (mIsFloating) { 2223 setLayout(WRAP_CONTENT, WRAP_CONTENT); 2224 setFlags(0, flagsToUpdate); 2225 } else { 2226 setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate); 2227 } 2228 2229 if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) { 2230 requestFeature(FEATURE_NO_TITLE); 2231 } else if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBar, false)) { 2232 // Don't allow an action bar if there is no title. 2233 requestFeature(FEATURE_ACTION_BAR); 2234 } 2235 2236 if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBarOverlay, false)) { 2237 requestFeature(FEATURE_ACTION_BAR_OVERLAY); 2238 } 2239 2240 if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionModeOverlay, false)) { 2241 requestFeature(FEATURE_ACTION_MODE_OVERLAY); 2242 } 2243 2244 if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) { 2245 setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags())); 2246 } 2247 2248 if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) { 2249 setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags())); 2250 } 2251 2252 if (a.getBoolean(com.android.internal.R.styleable.Window_windowEnableSplitTouch, 2253 getContext().getApplicationInfo().targetSdkVersion 2254 >= android.os.Build.VERSION_CODES.HONEYCOMB)) { 2255 setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags())); 2256 } 2257 2258 if (getContext().getApplicationInfo().targetSdkVersion 2259 < android.os.Build.VERSION_CODES.HONEYCOMB) { 2260 addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY); 2261 } 2262 2263 WindowManager.LayoutParams params = getAttributes(); 2264 2265 if (!hasSoftInputMode()) { 2266 params.softInputMode = a.getInt( 2267 com.android.internal.R.styleable.Window_windowSoftInputMode, 2268 params.softInputMode); 2269 } 2270 2271 if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled, 2272 mIsFloating)) { 2273 /* All dialogs should have the window dimmed */ 2274 if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) { 2275 params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; 2276 } 2277 params.dimAmount = a.getFloat( 2278 android.R.styleable.Window_backgroundDimAmount, 0.5f); 2279 } 2280 2281 if (params.windowAnimations == 0) { 2282 params.windowAnimations = a.getResourceId( 2283 com.android.internal.R.styleable.Window_windowAnimationStyle, 0); 2284 } 2285 2286 // The rest are only done if this window is not embedded; otherwise, 2287 // the values are inherited from our container. 2288 if (getContainer() == null) { 2289 if (mBackgroundDrawable == null) { 2290 if (mBackgroundResource == 0) { 2291 mBackgroundResource = a.getResourceId( 2292 com.android.internal.R.styleable.Window_windowBackground, 0); 2293 } 2294 if (mFrameResource == 0) { 2295 mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0); 2296 } 2297 if (false) { 2298 System.out.println("Background: " 2299 + Integer.toHexString(mBackgroundResource) + " Frame: " 2300 + Integer.toHexString(mFrameResource)); 2301 } 2302 } 2303 mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000); 2304 } 2305 2306 // Inflate the window decor. 2307 2308 int layoutResource; 2309 int features = getLocalFeatures(); 2310 // System.out.println("Features: 0x" + Integer.toHexString(features)); 2311 if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) { 2312 if (mIsFloating) { 2313 layoutResource = com.android.internal.R.layout.dialog_title_icons; 2314 } else { 2315 layoutResource = com.android.internal.R.layout.screen_title_icons; 2316 } 2317 // XXX Remove this once action bar supports these features. 2318 removeFeature(FEATURE_ACTION_BAR); 2319 // System.out.println("Title Icons!"); 2320 } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0 2321 && (features & (1 << FEATURE_ACTION_BAR)) == 0) { 2322 // Special case for a window with only a progress bar (and title). 2323 // XXX Need to have a no-title version of embedded windows. 2324 layoutResource = com.android.internal.R.layout.screen_progress; 2325 // System.out.println("Progress!"); 2326 } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) { 2327 // Special case for a window with a custom title. 2328 // If the window is floating, we need a dialog layout 2329 if (mIsFloating) { 2330 layoutResource = com.android.internal.R.layout.dialog_custom_title; 2331 } else { 2332 layoutResource = com.android.internal.R.layout.screen_custom_title; 2333 } 2334 // XXX Remove this once action bar supports these features. 2335 removeFeature(FEATURE_ACTION_BAR); 2336 } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) { 2337 // If no other features and not embedded, only need a title. 2338 // If the window is floating, we need a dialog layout 2339 if (mIsFloating) { 2340 layoutResource = com.android.internal.R.layout.dialog_title; 2341 } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) { 2342 if ((features & (1 << FEATURE_ACTION_BAR_OVERLAY)) != 0) { 2343 layoutResource = com.android.internal.R.layout.screen_action_bar_overlay; 2344 } else { 2345 layoutResource = com.android.internal.R.layout.screen_action_bar; 2346 } 2347 } else { 2348 layoutResource = com.android.internal.R.layout.screen_title; 2349 } 2350 // System.out.println("Title!"); 2351 } else { 2352 // Embedded, so no decoration is needed. 2353 layoutResource = com.android.internal.R.layout.screen_simple; 2354 // System.out.println("Simple!"); 2355 } 2356 2357 mDecor.startChanging(); 2358 2359 View in = mLayoutInflater.inflate(layoutResource, null); 2360 decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); 2361 2362 ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); 2363 if (contentParent == null) { 2364 throw new RuntimeException("Window couldn't find content container view"); 2365 } 2366 2367 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { 2368 ProgressBar progress = getCircularProgressBar(false); 2369 if (progress != null) { 2370 progress.setIndeterminate(true); 2371 } 2372 } 2373 2374 // Remaining setup -- of background and title -- that only applies 2375 // to top-level windows. 2376 if (getContainer() == null) { 2377 Drawable drawable = mBackgroundDrawable; 2378 if (mBackgroundResource != 0) { 2379 drawable = getContext().getResources().getDrawable(mBackgroundResource); 2380 } 2381 mDecor.setWindowBackground(drawable); 2382 drawable = null; 2383 if (mFrameResource != 0) { 2384 drawable = getContext().getResources().getDrawable(mFrameResource); 2385 } 2386 mDecor.setWindowFrame(drawable); 2387 2388 // System.out.println("Text=" + Integer.toHexString(mTextColor) + 2389 // " Sel=" + Integer.toHexString(mTextSelectedColor) + 2390 // " Title=" + Integer.toHexString(mTitleColor)); 2391 2392 if (mTitleColor == 0) { 2393 mTitleColor = mTextColor; 2394 } 2395 2396 if (mTitle != null) { 2397 setTitle(mTitle); 2398 } 2399 setTitleColor(mTitleColor); 2400 } 2401 2402 mDecor.finishChanging(); 2403 2404 return contentParent; 2405 } 2406 2407 private void installDecor() { 2408 if (mDecor == null) { 2409 mDecor = generateDecor(); 2410 mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); 2411 mDecor.setIsRootNamespace(true); 2412 } 2413 if (mContentParent == null) { 2414 mContentParent = generateLayout(mDecor); 2415 2416 mTitleView = (TextView)findViewById(com.android.internal.R.id.title); 2417 if (mTitleView != null) { 2418 if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) { 2419 View titleContainer = findViewById(com.android.internal.R.id.title_container); 2420 if (titleContainer != null) { 2421 titleContainer.setVisibility(View.GONE); 2422 } else { 2423 mTitleView.setVisibility(View.GONE); 2424 } 2425 if (mContentParent instanceof FrameLayout) { 2426 ((FrameLayout)mContentParent).setForeground(null); 2427 } 2428 } else { 2429 mTitleView.setText(mTitle); 2430 } 2431 } else { 2432 mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar); 2433 if (mActionBar != null) { 2434 if (mActionBar.getTitle() == null) { 2435 mActionBar.setWindowTitle(mTitle); 2436 } 2437 final int localFeatures = getLocalFeatures(); 2438 if ((localFeatures & (1 << FEATURE_PROGRESS)) != 0) { 2439 mActionBar.initProgress(); 2440 } 2441 if ((localFeatures & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { 2442 mActionBar.initIndeterminateProgress(); 2443 } 2444 // Post the panel invalidate for later; avoid application onCreateOptionsMenu 2445 // being called in the middle of onCreate or similar. 2446 mDecor.post(new Runnable() { 2447 public void run() { 2448 if (!isDestroyed()) { 2449 invalidatePanelMenu(FEATURE_ACTION_BAR); 2450 } 2451 } 2452 }); 2453 } 2454 } 2455 } 2456 } 2457 2458 private Drawable loadImageURI(Uri uri) { 2459 try { 2460 return Drawable.createFromStream( 2461 getContext().getContentResolver().openInputStream(uri), null); 2462 } catch (Exception e) { 2463 Log.w(TAG, "Unable to open content: " + uri); 2464 } 2465 return null; 2466 } 2467 2468 private DrawableFeatureState getDrawableState(int featureId, boolean required) { 2469 if ((getFeatures() & (1 << featureId)) == 0) { 2470 if (!required) { 2471 return null; 2472 } 2473 throw new RuntimeException("The feature has not been requested"); 2474 } 2475 2476 DrawableFeatureState[] ar; 2477 if ((ar = mDrawables) == null || ar.length <= featureId) { 2478 DrawableFeatureState[] nar = new DrawableFeatureState[featureId + 1]; 2479 if (ar != null) { 2480 System.arraycopy(ar, 0, nar, 0, ar.length); 2481 } 2482 mDrawables = ar = nar; 2483 } 2484 2485 DrawableFeatureState st = ar[featureId]; 2486 if (st == null) { 2487 ar[featureId] = st = new DrawableFeatureState(featureId); 2488 } 2489 return st; 2490 } 2491 2492 /** 2493 * Gets a panel's state based on its feature ID. 2494 * 2495 * @param featureId The feature ID of the panel. 2496 * @param required Whether the panel is required (if it is required and it 2497 * isn't in our features, this throws an exception). 2498 * @return The panel state. 2499 */ 2500 private PanelFeatureState getPanelState(int featureId, boolean required) { 2501 return getPanelState(featureId, required, null); 2502 } 2503 2504 /** 2505 * Gets a panel's state based on its feature ID. 2506 * 2507 * @param featureId The feature ID of the panel. 2508 * @param required Whether the panel is required (if it is required and it 2509 * isn't in our features, this throws an exception). 2510 * @param convertPanelState Optional: If the panel state does not exist, use 2511 * this as the panel state. 2512 * @return The panel state. 2513 */ 2514 private PanelFeatureState getPanelState(int featureId, boolean required, 2515 PanelFeatureState convertPanelState) { 2516 if ((getFeatures() & (1 << featureId)) == 0) { 2517 if (!required) { 2518 return null; 2519 } 2520 throw new RuntimeException("The feature has not been requested"); 2521 } 2522 2523 PanelFeatureState[] ar; 2524 if ((ar = mPanels) == null || ar.length <= featureId) { 2525 PanelFeatureState[] nar = new PanelFeatureState[featureId + 1]; 2526 if (ar != null) { 2527 System.arraycopy(ar, 0, nar, 0, ar.length); 2528 } 2529 mPanels = ar = nar; 2530 } 2531 2532 PanelFeatureState st = ar[featureId]; 2533 if (st == null) { 2534 ar[featureId] = st = (convertPanelState != null) 2535 ? convertPanelState 2536 : new PanelFeatureState(featureId); 2537 } 2538 return st; 2539 } 2540 2541 @Override 2542 public final void setChildDrawable(int featureId, Drawable drawable) { 2543 DrawableFeatureState st = getDrawableState(featureId, true); 2544 st.child = drawable; 2545 updateDrawable(featureId, st, false); 2546 } 2547 2548 @Override 2549 public final void setChildInt(int featureId, int value) { 2550 updateInt(featureId, value, false); 2551 } 2552 2553 @Override 2554 public boolean isShortcutKey(int keyCode, KeyEvent event) { 2555 PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); 2556 return st.menu != null && st.menu.isShortcutKey(keyCode, event); 2557 } 2558 2559 private void updateDrawable(int featureId, DrawableFeatureState st, boolean fromResume) { 2560 // Do nothing if the decor is not yet installed... an update will 2561 // need to be forced when we eventually become active. 2562 if (mContentParent == null) { 2563 return; 2564 } 2565 2566 final int featureMask = 1 << featureId; 2567 2568 if ((getFeatures() & featureMask) == 0 && !fromResume) { 2569 return; 2570 } 2571 2572 Drawable drawable = null; 2573 if (st != null) { 2574 drawable = st.child; 2575 if (drawable == null) 2576 drawable = st.local; 2577 if (drawable == null) 2578 drawable = st.def; 2579 } 2580 if ((getLocalFeatures() & featureMask) == 0) { 2581 if (getContainer() != null) { 2582 if (isActive() || fromResume) { 2583 getContainer().setChildDrawable(featureId, drawable); 2584 } 2585 } 2586 } else if (st != null && (st.cur != drawable || st.curAlpha != st.alpha)) { 2587 // System.out.println("Drawable changed: old=" + st.cur 2588 // + ", new=" + drawable); 2589 st.cur = drawable; 2590 st.curAlpha = st.alpha; 2591 onDrawableChanged(featureId, drawable, st.alpha); 2592 } 2593 } 2594 2595 private void updateInt(int featureId, int value, boolean fromResume) { 2596 2597 // Do nothing if the decor is not yet installed... an update will 2598 // need to be forced when we eventually become active. 2599 if (mContentParent == null) { 2600 return; 2601 } 2602 2603 final int featureMask = 1 << featureId; 2604 2605 if ((getFeatures() & featureMask) == 0 && !fromResume) { 2606 return; 2607 } 2608 2609 if ((getLocalFeatures() & featureMask) == 0) { 2610 if (getContainer() != null) { 2611 getContainer().setChildInt(featureId, value); 2612 } 2613 } else { 2614 onIntChanged(featureId, value); 2615 } 2616 } 2617 2618 private ImageView getLeftIconView() { 2619 if (mLeftIconView != null) { 2620 return mLeftIconView; 2621 } 2622 if (mContentParent == null) { 2623 installDecor(); 2624 } 2625 return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon)); 2626 } 2627 2628 private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) { 2629 if (mCircularProgressBar != null) { 2630 return mCircularProgressBar; 2631 } 2632 if (mContentParent == null && shouldInstallDecor) { 2633 installDecor(); 2634 } 2635 mCircularProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress_circular); 2636 if (mCircularProgressBar != null) { 2637 mCircularProgressBar.setVisibility(View.INVISIBLE); 2638 } 2639 return mCircularProgressBar; 2640 } 2641 2642 private ProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) { 2643 if (mHorizontalProgressBar != null) { 2644 return mHorizontalProgressBar; 2645 } 2646 if (mContentParent == null && shouldInstallDecor) { 2647 installDecor(); 2648 } 2649 mHorizontalProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress_horizontal); 2650 if (mHorizontalProgressBar != null) { 2651 mHorizontalProgressBar.setVisibility(View.INVISIBLE); 2652 } 2653 return mHorizontalProgressBar; 2654 } 2655 2656 private ImageView getRightIconView() { 2657 if (mRightIconView != null) { 2658 return mRightIconView; 2659 } 2660 if (mContentParent == null) { 2661 installDecor(); 2662 } 2663 return (mRightIconView = (ImageView)findViewById(com.android.internal.R.id.right_icon)); 2664 } 2665 2666 /** 2667 * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)} 2668 * callback. This method will grab whatever extra state is needed for the 2669 * callback that isn't given in the parameters. If the panel is not open, 2670 * this will not perform the callback. 2671 * 2672 * @param featureId Feature ID of the panel that was closed. Must be given. 2673 * @param panel Panel that was closed. Optional but useful if there is no 2674 * menu given. 2675 * @param menu The menu that was closed. Optional, but give if you have. 2676 */ 2677 private void callOnPanelClosed(int featureId, PanelFeatureState panel, Menu menu) { 2678 final Callback cb = getCallback(); 2679 if (cb == null) 2680 return; 2681 2682 // Try to get a menu 2683 if (menu == null) { 2684 // Need a panel to grab the menu, so try to get that 2685 if (panel == null) { 2686 if ((featureId >= 0) && (featureId < mPanels.length)) { 2687 panel = mPanels[featureId]; 2688 } 2689 } 2690 2691 if (panel != null) { 2692 // menu still may be null, which is okay--we tried our best 2693 menu = panel.menu; 2694 } 2695 } 2696 2697 // If the panel is not open, do not callback 2698 if ((panel != null) && (!panel.isOpen)) 2699 return; 2700 2701 cb.onPanelClosed(featureId, menu); 2702 } 2703 2704 /** 2705 * Helper method for adding launch-search to most applications. Opens the 2706 * search window using default settings. 2707 * 2708 * @return true if search window opened 2709 */ 2710 private boolean launchDefaultSearch() { 2711 final Callback cb = getCallback(); 2712 if (cb == null) { 2713 return false; 2714 } else { 2715 sendCloseSystemWindows("search"); 2716 return cb.onSearchRequested(); 2717 } 2718 } 2719 2720 @Override 2721 public void setVolumeControlStream(int streamType) { 2722 mVolumeControlStreamType = streamType; 2723 } 2724 2725 @Override 2726 public int getVolumeControlStream() { 2727 return mVolumeControlStreamType; 2728 } 2729 2730 private static final class DrawableFeatureState { 2731 DrawableFeatureState(int _featureId) { 2732 featureId = _featureId; 2733 } 2734 2735 final int featureId; 2736 2737 int resid; 2738 2739 Uri uri; 2740 2741 Drawable local; 2742 2743 Drawable child; 2744 2745 Drawable def; 2746 2747 Drawable cur; 2748 2749 int alpha = 255; 2750 2751 int curAlpha = 255; 2752 } 2753 2754 private static final class PanelFeatureState { 2755 2756 /** Feature ID for this panel. */ 2757 int featureId; 2758 2759 // Information pulled from the style for this panel. 2760 2761 int background; 2762 2763 /** The background when the panel spans the entire available width. */ 2764 int fullBackground; 2765 2766 int gravity; 2767 2768 int x; 2769 2770 int y; 2771 2772 int windowAnimations; 2773 2774 /** Dynamic state of the panel. */ 2775 DecorView decorView; 2776 2777 /** The panel that was returned by onCreatePanelView(). */ 2778 View createdPanelView; 2779 2780 /** The panel that we are actually showing. */ 2781 View shownPanelView; 2782 2783 /** Use {@link #setMenu} to set this. */ 2784 Menu menu; 2785 2786 /** 2787 * Whether the panel has been prepared (see 2788 * {@link PhoneWindow#preparePanel}). 2789 */ 2790 boolean isPrepared; 2791 2792 /** 2793 * Whether an item's action has been performed. This happens in obvious 2794 * scenarios (user clicks on menu item), but can also happen with 2795 * chording menu+(shortcut key). 2796 */ 2797 boolean isHandled; 2798 2799 boolean isOpen; 2800 2801 /** 2802 * True if the menu is in expanded mode, false if the menu is in icon 2803 * mode 2804 */ 2805 boolean isInExpandedMode; 2806 2807 public boolean qwertyMode; 2808 2809 boolean refreshDecorView; 2810 2811 boolean refreshMenuContent; 2812 2813 boolean wasLastOpen; 2814 2815 boolean wasLastExpanded; 2816 2817 /** 2818 * Contains the state of the menu when told to freeze. 2819 */ 2820 Bundle frozenMenuState; 2821 2822 PanelFeatureState(int featureId) { 2823 this.featureId = featureId; 2824 2825 refreshDecorView = false; 2826 } 2827 2828 void setStyle(Context context) { 2829 TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme); 2830 background = a.getResourceId( 2831 com.android.internal.R.styleable.Theme_panelBackground, 0); 2832 fullBackground = a.getResourceId( 2833 com.android.internal.R.styleable.Theme_panelFullBackground, 0); 2834 windowAnimations = a.getResourceId( 2835 com.android.internal.R.styleable.Theme_windowAnimationStyle, 0); 2836 a.recycle(); 2837 } 2838 2839 void setMenu(Menu menu) { 2840 this.menu = menu; 2841 2842 if (frozenMenuState != null) { 2843 ((MenuBuilder) menu).restoreHierarchyState(frozenMenuState); 2844 frozenMenuState = null; 2845 } 2846 } 2847 2848 Parcelable onSaveInstanceState() { 2849 SavedState savedState = new SavedState(); 2850 savedState.featureId = featureId; 2851 savedState.isOpen = isOpen; 2852 savedState.isInExpandedMode = isInExpandedMode; 2853 2854 if (menu != null) { 2855 savedState.menuState = new Bundle(); 2856 ((MenuBuilder) menu).saveHierarchyState(savedState.menuState); 2857 } 2858 2859 return savedState; 2860 } 2861 2862 void onRestoreInstanceState(Parcelable state) { 2863 SavedState savedState = (SavedState) state; 2864 featureId = savedState.featureId; 2865 wasLastOpen = savedState.isOpen; 2866 wasLastExpanded = savedState.isInExpandedMode; 2867 frozenMenuState = savedState.menuState; 2868 2869 /* 2870 * A LocalActivityManager keeps the same instance of this class around. 2871 * The first time the menu is being shown after restoring, the 2872 * Activity.onCreateOptionsMenu should be called. But, if it is the 2873 * same instance then menu != null and we won't call that method. 2874 * So, clear this. Also clear any cached views. 2875 */ 2876 menu = null; 2877 createdPanelView = null; 2878 shownPanelView = null; 2879 decorView = null; 2880 } 2881 2882 private static class SavedState implements Parcelable { 2883 int featureId; 2884 boolean isOpen; 2885 boolean isInExpandedMode; 2886 Bundle menuState; 2887 2888 public int describeContents() { 2889 return 0; 2890 } 2891 2892 public void writeToParcel(Parcel dest, int flags) { 2893 dest.writeInt(featureId); 2894 dest.writeInt(isOpen ? 1 : 0); 2895 dest.writeInt(isInExpandedMode ? 1 : 0); 2896 2897 if (isOpen) { 2898 dest.writeBundle(menuState); 2899 } 2900 } 2901 2902 private static SavedState readFromParcel(Parcel source) { 2903 SavedState savedState = new SavedState(); 2904 savedState.featureId = source.readInt(); 2905 savedState.isOpen = source.readInt() == 1; 2906 savedState.isInExpandedMode = source.readInt() == 1; 2907 2908 if (savedState.isOpen) { 2909 savedState.menuState = source.readBundle(); 2910 } 2911 2912 return savedState; 2913 } 2914 2915 public static final Parcelable.Creator<SavedState> CREATOR 2916 = new Parcelable.Creator<SavedState>() { 2917 public SavedState createFromParcel(Parcel in) { 2918 return readFromParcel(in); 2919 } 2920 2921 public SavedState[] newArray(int size) { 2922 return new SavedState[size]; 2923 } 2924 }; 2925 } 2926 2927 } 2928 2929 /** 2930 * Simple implementation of MenuBuilder.Callback that: 2931 * <li> Opens a submenu when selected. 2932 * <li> Calls back to the callback's onMenuItemSelected when an item is 2933 * selected. 2934 */ 2935 private final class DialogMenuCallback implements MenuBuilder.Callback { 2936 private int mFeatureId; 2937 private MenuDialogHelper mSubMenuHelper; 2938 2939 public DialogMenuCallback(int featureId) { 2940 mFeatureId = featureId; 2941 } 2942 2943 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 2944 if (allMenusAreClosing) { 2945 Callback callback = getCallback(); 2946 if (callback != null) callback.onPanelClosed(mFeatureId, menu); 2947 2948 if (menu == mContextMenu) { 2949 dismissContextMenu(); 2950 } 2951 2952 // Dismiss the submenu, if it is showing 2953 if (mSubMenuHelper != null) { 2954 mSubMenuHelper.dismiss(); 2955 mSubMenuHelper = null; 2956 } 2957 } 2958 } 2959 2960 public void onCloseSubMenu(SubMenuBuilder menu) { 2961 Callback callback = getCallback(); 2962 if (callback != null) callback.onPanelClosed(mFeatureId, menu.getRootMenu()); 2963 } 2964 2965 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { 2966 Callback callback = getCallback(); 2967 return (callback != null) && callback.onMenuItemSelected(mFeatureId, item); 2968 } 2969 2970 public void onMenuModeChange(MenuBuilder menu) { 2971 } 2972 2973 public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 2974 // Set a simple callback for the submenu 2975 subMenu.setCallback(this); 2976 2977 // The window manager will give us a valid window token 2978 mSubMenuHelper = new MenuDialogHelper(subMenu); 2979 mSubMenuHelper.show(null); 2980 2981 return true; 2982 } 2983 } 2984 2985 void sendCloseSystemWindows() { 2986 PhoneWindowManager.sendCloseSystemWindows(getContext(), null); 2987 } 2988 2989 void sendCloseSystemWindows(String reason) { 2990 PhoneWindowManager.sendCloseSystemWindows(getContext(), reason); 2991 } 2992 2993 private class ActionButtonSubmenu extends MenuPopupHelper implements Runnable { 2994 private SubMenuBuilder mSubMenu; 2995 2996 public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) { 2997 super(context, subMenu); 2998 mSubMenu = subMenu; 2999 } 3000 3001 @Override 3002 public void onDismiss() { 3003 super.onDismiss(); 3004 mSubMenu.getCallback().onCloseSubMenu(mSubMenu); 3005 mActionButtonPopup = null; 3006 } 3007 3008 @Override 3009 public void run() { 3010 show(); 3011 Callback cb = getCallback(); 3012 if (cb != null) { 3013 cb.onMenuOpened(FEATURE_ACTION_BAR, mSubMenu); 3014 } 3015 } 3016 } 3017} 3018