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