blob: 0f257d78d5f54831eaaf8319baa757da01230f97 [file] [log] [blame]
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001/*
Jeff Brown37df39a92015-02-25 15:42:31 -08002 * Copyright (C) 2006 The Android Open Source Project
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Adam Powell6711f3b2015-05-06 15:57:09 -070017package com.android.internal.policy;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080018
Romain Guycc6828c2010-01-08 15:06:37 -080019import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
svetoslavganov491293e2009-04-28 19:17:02 -070020import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
Dianne Hackbornc652de82013-02-15 16:32:56 -080021import static android.view.WindowManager.LayoutParams.*;
svetoslavganov491293e2009-04-28 19:17:02 -070022
Jorim Jaggib10e33f2015-02-04 21:57:40 +010023import android.app.ActivityManagerNative;
Dianne Hackbornfdf5b352014-10-08 17:43:48 -070024import android.app.SearchManager;
25import android.os.UserHandle;
Clara Bayarried2a54c2015-02-05 16:58:00 +000026
Phil Weaver396d5492016-03-22 17:53:50 -070027import android.text.TextUtils;
Adam Powell6711f3b2015-05-06 15:57:09 -070028import android.view.ContextThemeWrapper;
Adam Powell6711f3b2015-05-06 15:57:09 -070029import android.view.Gravity;
30import android.view.IRotationWatcher.Stub;
31import android.view.IWindowManager;
32import android.view.InputDevice;
33import android.view.InputEvent;
34import android.view.InputQueue;
35import android.view.KeyCharacterMap;
36import android.view.KeyEvent;
37import android.view.LayoutInflater;
38import android.view.Menu;
39import android.view.MenuItem;
40import android.view.MotionEvent;
41import android.view.SearchEvent;
42import android.view.SurfaceHolder.Callback2;
43import android.view.View;
44import android.view.ViewConfiguration;
45import android.view.ViewGroup;
46import android.view.ViewManager;
47import android.view.ViewParent;
48import android.view.ViewRootImpl;
Adam Powell6711f3b2015-05-06 15:57:09 -070049import android.view.Window;
Adam Powell6711f3b2015-05-06 15:57:09 -070050import android.view.WindowManager;
John Spurlockae3349e2013-10-18 17:34:42 -040051import com.android.internal.R;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080052import com.android.internal.view.menu.ContextMenuBuilder;
Adam Powell696cba52011-03-29 10:38:16 -070053import com.android.internal.view.menu.IconMenuPresenter;
Adam Powell640a66e2011-04-29 10:18:53 -070054import com.android.internal.view.menu.ListMenuPresenter;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080055import com.android.internal.view.menu.MenuBuilder;
56import com.android.internal.view.menu.MenuDialogHelper;
Alan Viverette021627e2015-11-25 14:22:00 -050057import com.android.internal.view.menu.MenuHelper;
Adam Powell696cba52011-03-29 10:38:16 -070058import com.android.internal.view.menu.MenuPresenter;
Adam Powell640a66e2011-04-29 10:18:53 -070059import com.android.internal.view.menu.MenuView;
Adam Powell4369e7d2014-05-17 14:16:08 -070060import com.android.internal.widget.DecorContentParent;
Will Haldean Brownca6234e2014-02-12 10:23:41 -080061import com.android.internal.widget.SwipeDismissLayout;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080062
Adrian Roosea562512014-05-05 13:33:03 +020063import android.app.ActivityManager;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080064import android.app.KeyguardManager;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080065import android.content.Context;
Tim Kilbourn0e5f1102015-06-05 16:18:09 -070066import android.content.Intent;
Aaron Whyte1fb617f2014-05-12 22:08:53 -070067import android.content.pm.PackageManager;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080068import android.content.res.Configuration;
Alan Viverette4b002d32014-06-03 17:32:19 -070069import android.content.res.Resources.Theme;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080070import android.content.res.TypedArray;
Adrian Roosea562512014-05-05 13:33:03 +020071import android.graphics.Color;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080072import android.graphics.drawable.Drawable;
73import android.media.AudioManager;
RoboErik55011652014-07-09 15:05:53 -070074import android.media.session.MediaController;
RoboErik55011652014-07-09 15:05:53 -070075import android.media.session.MediaSessionLegacyHelper;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080076import android.net.Uri;
77import android.os.Bundle;
Adam Powelldfee59a2011-08-05 20:48:30 -070078import android.os.Handler;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080079import android.os.Parcel;
80import android.os.Parcelable;
Adam Powelldfee59a2011-08-05 20:48:30 -070081import android.os.RemoteException;
82import android.os.ServiceManager;
George Mount31a21722014-03-24 17:44:36 -070083import android.transition.Scene;
84import android.transition.Transition;
85import android.transition.TransitionInflater;
86import android.transition.TransitionManager;
George Mount68f96d82014-07-31 13:13:10 -070087import android.transition.TransitionSet;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080088import android.util.AndroidRuntimeException;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080089import android.util.EventLog;
90import android.util.Log;
91import android.util.SparseArray;
Adam Powell85446e92010-10-22 17:43:56 -070092import android.util.TypedValue;
Alan Viveretteec6cf182015-08-13 15:31:57 -040093import android.view.accessibility.AccessibilityNodeInfo;
94import android.view.accessibility.AccessibilityNodeProvider;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080095import android.view.animation.Animation;
96import android.view.animation.AnimationUtils;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080097import android.widget.FrameLayout;
98import android.widget.ImageView;
99import android.widget.ProgressBar;
100import android.widget.TextView;
101
Adam Powelldfee59a2011-08-05 20:48:30 -0700102import java.lang.ref.WeakReference;
103import java.util.ArrayList;
104
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800105/**
106 * Android-specific Window.
107 * <p>
108 * todo: need to pull the generic functionality out into a base class
109 * in android.widget.
Jorim Jaggib10e33f2015-02-04 21:57:40 +0100110 *
111 * @hide
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800112 */
113public class PhoneWindow extends Window implements MenuBuilder.Callback {
svetoslavganov491293e2009-04-28 19:17:02 -0700114
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800115 private final static String TAG = "PhoneWindow";
116
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800117 private static final boolean DEBUG = false;
118
George Mounted1e01d2014-06-05 13:49:12 -0700119 private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300;
120
Adam Powell166c8e32014-07-01 17:37:48 -0700121 private static final int CUSTOM_TITLE_COMPATIBLE_FEATURES = DEFAULT_FEATURES |
122 (1 << FEATURE_CUSTOM_TITLE) |
123 (1 << FEATURE_CONTENT_TRANSITIONS) |
George Mount9826f632014-09-11 08:50:09 -0700124 (1 << FEATURE_ACTIVITY_TRANSITIONS) |
Adam Powell166c8e32014-07-01 17:37:48 -0700125 (1 << FEATURE_ACTION_MODE_OVERLAY);
126
George Mount68f96d82014-07-31 13:13:10 -0700127 private static final Transition USE_DEFAULT_TRANSITION = new TransitionSet();
128
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800129 /**
130 * Simple callback used by the context menu and its submenus. The options
131 * menu submenus do not use this (their behavior is more complex).
132 */
Alan Viverette77fb85e2015-12-14 11:42:44 -0500133 final PhoneWindowMenuCallback mContextMenuCallback = new PhoneWindowMenuCallback(this);
Dianne Hackborn60145272011-01-11 23:45:09 -0800134
135 final TypedValue mMinWidthMajor = new TypedValue();
136 final TypedValue mMinWidthMinor = new TypedValue();
Adam Powell40eec4c2012-02-15 17:10:58 -0800137 TypedValue mFixedWidthMajor;
138 TypedValue mFixedWidthMinor;
139 TypedValue mFixedHeightMajor;
140 TypedValue mFixedHeightMinor;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800141
142 // This is the top-level view of the window, containing the window decor.
143 private DecorView mDecor;
144
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700145 // When we reuse decor views, we need to recreate the content root. This happens when the decor
146 // view is requested, so we need to force the recreating without introducing an infinite loop.
147 private boolean mForceDecorInstall = false;
148
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800149 // This is the view in which the window contents are placed. It is either
150 // mDecor itself, or a child of mDecor where the contents go.
Wale Ogunwale8804af22015-11-17 09:18:15 -0800151 ViewGroup mContentParent;
Filip Gruszczynskif4bdaeb2016-01-06 14:34:00 -0800152 // Whether the client has explicitly set the content view. If false and mContentParent is not
153 // null, then the content parent was set due to window preservation.
154 private boolean mContentParentExplicitlySet = false;
Adrian Roosf5e9b5c2014-09-10 15:27:41 +0200155
Adam Powell6711f3b2015-05-06 15:57:09 -0700156 Callback2 mTakeSurfaceCallback;
George Mount0a778ed2013-12-13 13:35:36 -0800157
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700158 InputQueue.Callback mTakeInputQueueCallback;
George Mount0a778ed2013-12-13 13:35:36 -0800159
Wale Ogunwale8804af22015-11-17 09:18:15 -0800160 boolean mIsFloating;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700161 private boolean mIsTranslucent;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800162
163 private LayoutInflater mLayoutInflater;
164
165 private TextView mTitleView;
George Mount0a778ed2013-12-13 13:35:36 -0800166
Wale Ogunwale8804af22015-11-17 09:18:15 -0800167 DecorContentParent mDecorContentParent;
Adam Powell696cba52011-03-29 10:38:16 -0700168 private ActionMenuPresenterCallback mActionMenuPresenterCallback;
169 private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800170
Adam Powell18e905f2013-10-24 14:27:48 -0700171 private TransitionManager mTransitionManager;
Adam Powellcfbe9be2013-11-06 14:58:58 -0800172 private Scene mContentScene;
Adam Powell18e905f2013-10-24 14:27:48 -0700173
Adam Powell0a317e92013-06-13 13:15:43 -0700174 // The icon resource has been explicitly set elsewhere
175 // and should not be overwritten with a default.
Adam Powell04fe6eb2013-05-31 14:39:48 -0700176 static final int FLAG_RESOURCE_SET_ICON = 1 << 0;
Adam Powell0a317e92013-06-13 13:15:43 -0700177
178 // The logo resource has been explicitly set elsewhere
179 // and should not be overwritten with a default.
Adam Powell04fe6eb2013-05-31 14:39:48 -0700180 static final int FLAG_RESOURCE_SET_LOGO = 1 << 1;
Adam Powell0a317e92013-06-13 13:15:43 -0700181
182 // The icon resource is currently configured to use the system fallback
183 // as no default was previously specified. Anything can override this.
184 static final int FLAG_RESOURCE_SET_ICON_FALLBACK = 1 << 2;
185
Adam Powell04fe6eb2013-05-31 14:39:48 -0700186 int mResourcesSetFlags;
187 int mIconRes;
188 int mLogoRes;
189
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800190 private DrawableFeatureState[] mDrawables;
191
192 private PanelFeatureState[] mPanels;
193
194 /**
195 * The panel that is prepared or opened (the most recent one if there are
196 * multiple panels). Shortcuts will go to this panel. It gets set in
197 * {@link #preparePanel} and cleared in {@link #closePanel}.
198 */
Wale Ogunwale8804af22015-11-17 09:18:15 -0800199 PanelFeatureState mPreparedPanel;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800200
201 /**
202 * The keycode that is currently held down (as a modifier) for chording. If
203 * this is 0, there is no key held down.
204 */
Wale Ogunwale8804af22015-11-17 09:18:15 -0800205 int mPanelChordingKey;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800206
207 private ImageView mLeftIconView;
208
209 private ImageView mRightIconView;
210
211 private ProgressBar mCircularProgressBar;
212
213 private ProgressBar mHorizontalProgressBar;
214
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800215 int mBackgroundResource = 0;
216 int mBackgroundFallbackResource = 0;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800217
218 private Drawable mBackgroundDrawable;
219
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800220 private boolean mLoadElevation = true;
Alan Viverette49a22e82014-07-12 20:01:27 -0700221 private float mElevation;
222
Alan Viverette40982d42014-07-25 17:48:55 -0700223 /** Whether window content should be clipped to the background outline. */
224 private boolean mClipToOutline;
225
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800226 private int mFrameResource = 0;
227
228 private int mTextColor = 0;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800229 int mStatusBarColor = 0;
230 int mNavigationBarColor = 0;
Adrian Roos34e65442014-05-17 02:35:33 +0200231 private boolean mForcedStatusBarColor = false;
232 private boolean mForcedNavigationBarColor = false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800233
234 private CharSequence mTitle = null;
235
236 private int mTitleColor = 0;
237
Dianne Hackborncfaf8872011-01-18 13:57:54 -0800238 private boolean mAlwaysReadCloseOnTouchAttr = false;
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700239
Wale Ogunwale8804af22015-11-17 09:18:15 -0800240 ContextMenuBuilder mContextMenu;
Alan Viverette021627e2015-11-25 14:22:00 -0500241 MenuHelper mContextMenuHelper;
Adam Powell8515ee82010-11-30 14:09:55 -0800242 private boolean mClosingActionMenu;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800243
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800244 private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
RoboErik55011652014-07-09 15:05:53 -0700245 private MediaController mMediaController;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800246
Joe Onorato86f67862010-11-05 18:57:34 -0700247 private AudioManager mAudioManager;
248 private KeyguardManager mKeyguardManager;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800249
Adam Powell269248d2011-08-02 10:26:54 -0700250 private int mUiOptions = 0;
251
Adam Powell4b6d93f2012-09-18 18:34:08 -0700252 private boolean mInvalidatePanelMenuPosted;
253 private int mInvalidatePanelMenuFeatures;
254 private final Runnable mInvalidatePanelMenuRunnable = new Runnable() {
255 @Override public void run() {
256 for (int i = 0; i <= FEATURE_MAX; i++) {
257 if ((mInvalidatePanelMenuFeatures & 1 << i) != 0) {
258 doInvalidatePanelMenu(i);
259 }
260 }
261 mInvalidatePanelMenuPosted = false;
262 mInvalidatePanelMenuFeatures = 0;
263 }
264 };
265
George Mount68f96d82014-07-31 13:13:10 -0700266 private Transition mEnterTransition = null;
267 private Transition mReturnTransition = USE_DEFAULT_TRANSITION;
268 private Transition mExitTransition = null;
269 private Transition mReenterTransition = USE_DEFAULT_TRANSITION;
270 private Transition mSharedElementEnterTransition = null;
271 private Transition mSharedElementReturnTransition = USE_DEFAULT_TRANSITION;
272 private Transition mSharedElementExitTransition = null;
273 private Transition mSharedElementReenterTransition = USE_DEFAULT_TRANSITION;
George Mountc03da0e2014-08-22 17:04:02 -0700274 private Boolean mAllowReturnTransitionOverlap;
George Mount31a21722014-03-24 17:44:36 -0700275 private Boolean mAllowEnterTransitionOverlap;
George Mounted1e01d2014-06-05 13:49:12 -0700276 private long mBackgroundFadeDurationMillis = -1;
George Mountb89d5cc2014-08-18 16:50:50 -0700277 private Boolean mSharedElementsUseOverlay;
George Mount0a778ed2013-12-13 13:35:36 -0800278
Jorim Jaggia16cc152015-06-01 16:55:05 -0700279 private boolean mIsStartingWindow;
Filip Gruszczynski0daf2102015-09-29 08:39:07 -0700280 private int mTheme = -1;
Jorim Jaggia16cc152015-06-01 16:55:05 -0700281
Filip Gruszczynski3dec0812015-12-09 08:42:41 -0800282 private int mDecorCaptionShade = DECOR_CAPTION_SHADE_AUTO;
283
Filip Gruszczynski796b8c12015-12-22 14:46:21 -0800284 private boolean mUseDecorContext = false;
285
Adam Powelldfee59a2011-08-05 20:48:30 -0700286 static class WindowManagerHolder {
287 static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
288 ServiceManager.getService("window"));
289 }
290
291 static final RotationWatcher sRotationWatcher = new RotationWatcher();
292
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800293 public PhoneWindow(Context context) {
294 super(context);
295 mLayoutInflater = LayoutInflater.from(context);
296 }
297
Filip Gruszczynski796b8c12015-12-22 14:46:21 -0800298 /**
299 * Constructor for main window of an activity.
300 */
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700301 public PhoneWindow(Context context, Window preservedWindow) {
302 this(context);
Filip Gruszczynski796b8c12015-12-22 14:46:21 -0800303 // Only main activity windows use decor context, all the other windows depend on whatever
304 // context that was given to them.
305 mUseDecorContext = true;
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700306 if (preservedWindow != null) {
307 mDecor = (DecorView) preservedWindow.getDecorView();
308 mElevation = preservedWindow.getElevation();
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800309 mLoadElevation = false;
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700310 mForceDecorInstall = true;
Chong Zhanga8be1b92015-09-29 13:54:44 -0700311 // If we're preserving window, carry over the app token from the preserved
312 // window, as we'll be skipping the addView in handleResumeActivity(), and
313 // the token will not be updated as for a new window.
314 getAttributes().token = preservedWindow.getAttributes().token;
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700315 }
316 }
317
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800318 @Override
319 public final void setContainer(Window container) {
320 super.setContainer(container);
321 }
322
323 @Override
324 public boolean requestFeature(int featureId) {
Filip Gruszczynskif4bdaeb2016-01-06 14:34:00 -0800325 if (mContentParentExplicitlySet) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800326 throw new AndroidRuntimeException("requestFeature() must be called before adding content");
327 }
328 final int features = getFeatures();
Adam Powell166c8e32014-07-01 17:37:48 -0700329 final int newFeatures = features | (1 << featureId);
330 if ((newFeatures & (1 << FEATURE_CUSTOM_TITLE)) != 0 &&
331 (newFeatures & ~CUSTOM_TITLE_COMPATIBLE_FEATURES) != 0) {
332 // Another feature is enabled and the user is trying to enable the custom title feature
333 // or custom title feature is enabled and the user is trying to enable another feature
334 throw new AndroidRuntimeException(
335 "You cannot combine custom titles with other title features");
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800336 }
Adam Powellf4a6ec42010-08-24 14:18:10 -0700337 if ((features & (1 << FEATURE_NO_TITLE)) != 0 && featureId == FEATURE_ACTION_BAR) {
338 return false; // Ignore. No title dominates.
339 }
340 if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_NO_TITLE) {
341 // Remove the action bar feature if we have no title. No title dominates.
342 removeFeature(FEATURE_ACTION_BAR);
343 }
Will Haldean Brownca6234e2014-02-12 10:23:41 -0800344
345 if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_SWIPE_TO_DISMISS) {
346 throw new AndroidRuntimeException(
347 "You cannot combine swipe dismissal and the action bar.");
348 }
349 if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0 && featureId == FEATURE_ACTION_BAR) {
350 throw new AndroidRuntimeException(
351 "You cannot combine swipe dismissal and the action bar.");
352 }
Aaron Whyte1fb617f2014-05-12 22:08:53 -0700353
354 if (featureId == FEATURE_INDETERMINATE_PROGRESS &&
355 getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
356 throw new AndroidRuntimeException("You cannot use indeterminate progress on a watch.");
357 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800358 return super.requestFeature(featureId);
359 }
360
361 @Override
Adam Powell269248d2011-08-02 10:26:54 -0700362 public void setUiOptions(int uiOptions) {
363 mUiOptions = uiOptions;
364 }
365
366 @Override
Adam Powelle43fca92011-08-16 12:57:01 -0700367 public void setUiOptions(int uiOptions, int mask) {
368 mUiOptions = (mUiOptions & ~mask) | (uiOptions & mask);
369 }
370
371 @Override
Adam Powellcfbe9be2013-11-06 14:58:58 -0800372 public TransitionManager getTransitionManager() {
373 return mTransitionManager;
374 }
375
376 @Override
377 public void setTransitionManager(TransitionManager tm) {
378 mTransitionManager = tm;
379 }
380
381 @Override
382 public Scene getContentScene() {
383 return mContentScene;
384 }
385
386 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800387 public void setContentView(int layoutResID) {
Adam Powell18e905f2013-10-24 14:27:48 -0700388 // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
389 // decor, when theme attributes and the like are crystalized. Do not check the feature
390 // before this happens.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800391 if (mContentParent == null) {
392 installDecor();
Adam Powell18e905f2013-10-24 14:27:48 -0700393 } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800394 mContentParent.removeAllViews();
395 }
Adam Powell18e905f2013-10-24 14:27:48 -0700396
397 if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
398 final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
399 getContext());
Adam Powellcfbe9be2013-11-06 14:58:58 -0800400 transitionTo(newScene);
Adam Powell18e905f2013-10-24 14:27:48 -0700401 } else {
402 mLayoutInflater.inflate(layoutResID, mContentParent);
403 }
Adam Powell41607d52015-06-17 13:37:06 -0700404 mContentParent.requestApplyInsets();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800405 final Callback cb = getCallback();
Dianne Hackbornb66ad572011-03-01 17:10:30 -0800406 if (cb != null && !isDestroyed()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800407 cb.onContentChanged();
408 }
Filip Gruszczynskif4bdaeb2016-01-06 14:34:00 -0800409 mContentParentExplicitlySet = true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800410 }
411
412 @Override
413 public void setContentView(View view) {
Romain Guycc6828c2010-01-08 15:06:37 -0800414 setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800415 }
416
417 @Override
418 public void setContentView(View view, ViewGroup.LayoutParams params) {
Adam Powell18e905f2013-10-24 14:27:48 -0700419 // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
420 // decor, when theme attributes and the like are crystalized. Do not check the feature
421 // before this happens.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800422 if (mContentParent == null) {
423 installDecor();
Adam Powell18e905f2013-10-24 14:27:48 -0700424 } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800425 mContentParent.removeAllViews();
426 }
Adam Powell18e905f2013-10-24 14:27:48 -0700427
428 if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
429 view.setLayoutParams(params);
430 final Scene newScene = new Scene(mContentParent, view);
Adam Powellcfbe9be2013-11-06 14:58:58 -0800431 transitionTo(newScene);
Adam Powell18e905f2013-10-24 14:27:48 -0700432 } else {
433 mContentParent.addView(view, params);
434 }
Adam Powell41607d52015-06-17 13:37:06 -0700435 mContentParent.requestApplyInsets();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800436 final Callback cb = getCallback();
Dianne Hackbornb66ad572011-03-01 17:10:30 -0800437 if (cb != null && !isDestroyed()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800438 cb.onContentChanged();
439 }
Filip Gruszczynskif4bdaeb2016-01-06 14:34:00 -0800440 mContentParentExplicitlySet = true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800441 }
442
443 @Override
444 public void addContentView(View view, ViewGroup.LayoutParams params) {
445 if (mContentParent == null) {
446 installDecor();
447 }
Adam Powell18e905f2013-10-24 14:27:48 -0700448 if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
449 // TODO Augment the scenes/transitions API to support this.
George Mount7e208842014-07-02 07:22:43 -0700450 Log.v(TAG, "addContentView does not support content transitions");
Adam Powell18e905f2013-10-24 14:27:48 -0700451 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800452 mContentParent.addView(view, params);
Adam Powell41607d52015-06-17 13:37:06 -0700453 mContentParent.requestApplyInsets();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800454 final Callback cb = getCallback();
Dianne Hackbornb66ad572011-03-01 17:10:30 -0800455 if (cb != null && !isDestroyed()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800456 cb.onContentChanged();
457 }
458 }
459
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800460 @Override
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700461 public void clearContentView() {
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800462 if (mDecor != null) {
463 mDecor.clearContentView();
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700464 }
465 }
466
Adam Powellcfbe9be2013-11-06 14:58:58 -0800467 private void transitionTo(Scene scene) {
George Mount0a778ed2013-12-13 13:35:36 -0800468 if (mContentScene == null) {
469 scene.enter();
Adam Powellcfbe9be2013-11-06 14:58:58 -0800470 } else {
471 mTransitionManager.transitionTo(scene);
472 }
473 mContentScene = scene;
474 }
475
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800476 @Override
477 public View getCurrentFocus() {
478 return mDecor != null ? mDecor.findFocus() : null;
479 }
480
481 @Override
Adam Powell6711f3b2015-05-06 15:57:09 -0700482 public void takeSurface(Callback2 callback) {
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700483 mTakeSurfaceCallback = callback;
484 }
George Mount0a778ed2013-12-13 13:35:36 -0800485
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700486 public void takeInputQueue(InputQueue.Callback callback) {
487 mTakeInputQueueCallback = callback;
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700488 }
George Mount0a778ed2013-12-13 13:35:36 -0800489
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700490 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800491 public boolean isFloating() {
492 return mIsFloating;
493 }
494
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700495 public boolean isTranslucent() {
496 return mIsTranslucent;
497 }
498
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800499 /**
500 * Return a LayoutInflater instance that can be used to inflate XML view layout
501 * resources for use in this Window.
502 *
503 * @return LayoutInflater The shared LayoutInflater.
504 */
505 @Override
506 public LayoutInflater getLayoutInflater() {
507 return mLayoutInflater;
508 }
509
510 @Override
511 public void setTitle(CharSequence title) {
512 if (mTitleView != null) {
513 mTitleView.setText(title);
Adam Powell4369e7d2014-05-17 14:16:08 -0700514 } else if (mDecorContentParent != null) {
515 mDecorContentParent.setWindowTitle(title);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800516 }
517 mTitle = title;
Phil Weaver396d5492016-03-22 17:53:50 -0700518 WindowManager.LayoutParams params = getAttributes();
519 if (!TextUtils.equals(title, params.getTitle())) {
520 params.setTitle(title);
521 dispatchWindowAttributesChanged(getAttributes());
522 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800523 }
524
525 @Override
Alan Viverette2525d9c2013-11-15 14:42:19 -0800526 @Deprecated
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800527 public void setTitleColor(int textColor) {
528 if (mTitleView != null) {
529 mTitleView.setTextColor(textColor);
530 }
531 mTitleColor = textColor;
532 }
533
534 /**
535 * Prepares the panel to either be opened or chorded. This creates the Menu
536 * instance for the panel and populates it via the Activity callbacks.
537 *
538 * @param st The panel state to prepare.
539 * @param event The event that triggered the preparing of the panel.
540 * @return Whether the panel was prepared. If the panel should not be shown,
541 * returns false.
542 */
543 public final boolean preparePanel(PanelFeatureState st, KeyEvent event) {
Dianne Hackbornb66ad572011-03-01 17:10:30 -0800544 if (isDestroyed()) {
545 return false;
546 }
547
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800548 // Already prepared (isPrepared will be reset to false later)
Adam Powellc6d51882011-10-13 11:33:24 -0700549 if (st.isPrepared) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800550 return true;
Adam Powellc6d51882011-10-13 11:33:24 -0700551 }
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700552
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800553 if ((mPreparedPanel != null) && (mPreparedPanel != st)) {
554 // Another Panel is prepared and possibly open, so close it
555 closePanel(mPreparedPanel, false);
556 }
557
558 final Callback cb = getCallback();
559
560 if (cb != null) {
561 st.createdPanelView = cb.onCreatePanelView(st.featureId);
562 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800563
Adam Powell8c16aa92013-04-04 10:47:52 -0700564 final boolean isActionBarMenu =
565 (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR);
566
Adam Powell4369e7d2014-05-17 14:16:08 -0700567 if (isActionBarMenu && mDecorContentParent != null) {
Adam Powell8c16aa92013-04-04 10:47:52 -0700568 // Enforce ordering guarantees around events so that the action bar never
569 // dispatches menu-related events before the panel is prepared.
Adam Powell4369e7d2014-05-17 14:16:08 -0700570 mDecorContentParent.setMenuPrepared();
Adam Powell8c16aa92013-04-04 10:47:52 -0700571 }
572
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800573 if (st.createdPanelView == null) {
574 // Init the panel state's menu--return false if init failed
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700575 if (st.menu == null || st.refreshMenuContent) {
576 if (st.menu == null) {
577 if (!initializePanelMenu(st) || (st.menu == null)) {
578 return false;
579 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800580 }
Adam Powell696cba52011-03-29 10:38:16 -0700581
Adam Powell4369e7d2014-05-17 14:16:08 -0700582 if (isActionBarMenu && mDecorContentParent != null) {
Adam Powellccdd4ee2011-07-27 20:05:14 -0700583 if (mActionMenuPresenterCallback == null) {
584 mActionMenuPresenterCallback = new ActionMenuPresenterCallback();
585 }
Adam Powell4369e7d2014-05-17 14:16:08 -0700586 mDecorContentParent.setMenu(st.menu, mActionMenuPresenterCallback);
Adam Powellccdd4ee2011-07-27 20:05:14 -0700587 }
588
Adam Powell696cba52011-03-29 10:38:16 -0700589 // Call callback, and return if it doesn't want to display menu.
590
591 // Creating the panel menu will involve a lot of manipulation;
592 // don't dispatch change events to presenters until we're done.
593 st.menu.stopDispatchingItemsChanged();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800594 if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) {
595 // Ditch the menu created above
Adam Powell1d07e162011-09-07 20:46:24 -0700596 st.setMenu(null);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800597
Adam Powell4369e7d2014-05-17 14:16:08 -0700598 if (isActionBarMenu && mDecorContentParent != null) {
Adam Powell84f49362011-08-18 11:09:57 -0700599 // Don't show it in the action bar either
Adam Powell4369e7d2014-05-17 14:16:08 -0700600 mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
Adam Powell84f49362011-08-18 11:09:57 -0700601 }
Adam Powellf35d0492011-08-17 13:56:47 -0700602
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800603 return false;
604 }
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700605
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700606 st.refreshMenuContent = false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800607 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800608
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800609 // Callback and return if the callback does not want to show the menu
Adam Powell696cba52011-03-29 10:38:16 -0700610
611 // Preparing the panel menu can involve a lot of manipulation;
612 // don't dispatch change events to presenters until we're done.
613 st.menu.stopDispatchingItemsChanged();
Adam Powell97a30012011-08-09 17:15:48 -0700614
615 // Restore action view state before we prepare. This gives apps
616 // an opportunity to override frozen/restored state in onPrepare.
617 if (st.frozenActionViewState != null) {
618 st.menu.restoreActionViewStates(st.frozenActionViewState);
619 st.frozenActionViewState = null;
620 }
621
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800622 if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) {
Adam Powell4369e7d2014-05-17 14:16:08 -0700623 if (isActionBarMenu && mDecorContentParent != null) {
Adam Powell84f49362011-08-18 11:09:57 -0700624 // The app didn't want to show the menu for now but it still exists.
625 // Clear it out of the action bar.
Adam Powell4369e7d2014-05-17 14:16:08 -0700626 mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
Adam Powell84f49362011-08-18 11:09:57 -0700627 }
Adam Powell696cba52011-03-29 10:38:16 -0700628 st.menu.startDispatchingItemsChanged();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800629 return false;
630 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800631
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800632 // Set the proper keymap
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800633 KeyCharacterMap kmap = KeyCharacterMap.load(
634 event != null ? event.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800635 st.qwertyMode = kmap.getKeyboardType() != KeyCharacterMap.NUMERIC;
636 st.menu.setQwertyMode(st.qwertyMode);
Adam Powell89b09da2011-07-27 11:55:29 -0700637 st.menu.startDispatchingItemsChanged();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800638 }
639
640 // Set other state
641 st.isPrepared = true;
642 st.isHandled = false;
643 mPreparedPanel = st;
644
645 return true;
646 }
647
648 @Override
649 public void onConfigurationChanged(Configuration newConfig) {
Adam Powell6c6f5752010-08-20 18:34:46 -0700650 // Action bars handle their own menu state
Adam Powell4369e7d2014-05-17 14:16:08 -0700651 if (mDecorContentParent == null) {
Adam Powell6c6f5752010-08-20 18:34:46 -0700652 PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
653 if ((st != null) && (st.menu != null)) {
Adam Powell6c6f5752010-08-20 18:34:46 -0700654 if (st.isOpen) {
655 // Freeze state
656 final Bundle state = new Bundle();
Adam Powell696cba52011-03-29 10:38:16 -0700657 if (st.iconMenuPresenter != null) {
658 st.iconMenuPresenter.saveHierarchyState(state);
659 }
Adam Powelldfee59a2011-08-05 20:48:30 -0700660 if (st.listMenuPresenter != null) {
661 st.listMenuPresenter.saveHierarchyState(state);
Adam Powell696cba52011-03-29 10:38:16 -0700662 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800663
Adam Powell6c6f5752010-08-20 18:34:46 -0700664 // Remove the menu views since they need to be recreated
665 // according to the new configuration
666 clearMenuViews(st);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800667
Adam Powell6c6f5752010-08-20 18:34:46 -0700668 // Re-open the same menu
669 reopenMenu(false);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800670
Adam Powell6c6f5752010-08-20 18:34:46 -0700671 // Restore state
Adam Powell696cba52011-03-29 10:38:16 -0700672 if (st.iconMenuPresenter != null) {
673 st.iconMenuPresenter.restoreHierarchyState(state);
674 }
Adam Powelldfee59a2011-08-05 20:48:30 -0700675 if (st.listMenuPresenter != null) {
676 st.listMenuPresenter.restoreHierarchyState(state);
Adam Powell696cba52011-03-29 10:38:16 -0700677 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800678
Adam Powell6c6f5752010-08-20 18:34:46 -0700679 } else {
680 // Clear menu views so on next menu opening, it will use
681 // the proper layout
682 clearMenuViews(st);
683 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800684 }
685 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800686 }
687
Wale Ogunwaleeb6722c2015-12-08 11:43:43 -0800688 @Override
Andrii Kulian933076d2016-03-29 17:04:42 -0700689 public void onMultiWindowModeChanged() {
Wale Ogunwaleeb6722c2015-12-08 11:43:43 -0800690 if (mDecor != null) {
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -0800691 mDecor.onConfigurationChanged(getContext().getResources().getConfiguration());
Wale Ogunwaleeb6722c2015-12-08 11:43:43 -0800692 }
693 }
694
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100695 @Override
696 public void reportActivityRelaunched() {
697 if (mDecor != null && mDecor.getViewRootImpl() != null) {
698 mDecor.getViewRootImpl().reportActivityRelaunched();
699 }
700 }
701
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800702 private static void clearMenuViews(PanelFeatureState st) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800703 // This can be called on config changes, so we should make sure
704 // the views will be reconstructed based on the new orientation, etc.
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800705
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800706 // Allow the callback to create a new panel view
707 st.createdPanelView = null;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800708
709 // Causes the decor view to be recreated
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800710 st.refreshDecorView = true;
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700711
Adam Powell696cba52011-03-29 10:38:16 -0700712 st.clearMenuPresenters();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800713 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800714
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800715 @Override
716 public final void openPanel(int featureId, KeyEvent event) {
Adam Powell4369e7d2014-05-17 14:16:08 -0700717 if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
718 mDecorContentParent.canShowOverflowMenu() &&
Adam Powell5fcf5b92013-09-11 08:45:36 -0700719 !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
Adam Powell4369e7d2014-05-17 14:16:08 -0700720 mDecorContentParent.showOverflowMenu();
Adam Powellf75eeb22010-08-10 15:59:40 -0700721 } else {
722 openPanel(getPanelState(featureId, true), event);
723 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800724 }
725
Adam Powell5fcf5b92013-09-11 08:45:36 -0700726 private void openPanel(final PanelFeatureState st, KeyEvent event) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800727 // System.out.println("Open panel: isOpen=" + st.isOpen);
728
729 // Already open, return
Dianne Hackbornb66ad572011-03-01 17:10:30 -0800730 if (st.isOpen || isDestroyed()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800731 return;
732 }
733
Adam Powell0d69fae2011-01-08 15:07:08 -0800734 // Don't open an options panel for honeycomb apps on xlarge devices.
735 // (The app should be using an action bar for menu items.)
736 if (st.featureId == FEATURE_OPTIONS_PANEL) {
737 Context context = getContext();
738 Configuration config = context.getResources().getConfiguration();
739 boolean isXLarge = (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) ==
740 Configuration.SCREENLAYOUT_SIZE_XLARGE;
741 boolean isHoneycombApp = context.getApplicationInfo().targetSdkVersion >=
742 android.os.Build.VERSION_CODES.HONEYCOMB;
743
744 if (isXLarge && isHoneycombApp) {
745 return;
746 }
747 }
748
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800749 Callback cb = getCallback();
750 if ((cb != null) && (!cb.onMenuOpened(st.featureId, st.menu))) {
751 // Callback doesn't want the menu to open, reset any state
752 closePanel(st, true);
753 return;
754 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800755
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800756 final WindowManager wm = getWindowManager();
757 if (wm == null) {
758 return;
759 }
760
761 // Prepare panel (should have been done before, but just in case)
762 if (!preparePanel(st, event)) {
763 return;
764 }
765
Adam Powella3e3c532011-06-22 11:21:54 -0700766 int width = WRAP_CONTENT;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800767 if (st.decorView == null || st.refreshDecorView) {
768 if (st.decorView == null) {
769 // Initialize the panel decor, this will populate st.decorView
770 if (!initializePanelDecor(st) || (st.decorView == null))
771 return;
772 } else if (st.refreshDecorView && (st.decorView.getChildCount() > 0)) {
773 // Decor needs refreshing, so remove its views
774 st.decorView.removeAllViews();
775 }
776
777 // This will populate st.shownPanelView
Adam Powell526b9312011-04-22 15:42:05 -0700778 if (!initializePanelContent(st) || !st.hasPanelItems()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800779 return;
780 }
781
782 ViewGroup.LayoutParams lp = st.shownPanelView.getLayoutParams();
783 if (lp == null) {
784 lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
785 }
786
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800787 int backgroundResId;
Romain Guycc6828c2010-01-08 15:06:37 -0800788 if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800789 // If the contents is fill parent for the width, set the
790 // corresponding background
791 backgroundResId = st.fullBackground;
Adam Powella3e3c532011-06-22 11:21:54 -0700792 width = MATCH_PARENT;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800793 } else {
794 // Otherwise, set the normal panel background
795 backgroundResId = st.background;
796 }
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800797 st.decorView.setWindowBackground(getContext().getDrawable(
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800798 backgroundResId));
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800799
Adam Powella60314c2012-05-15 14:33:13 -0700800 ViewParent shownPanelParent = st.shownPanelView.getParent();
801 if (shownPanelParent != null && shownPanelParent instanceof ViewGroup) {
802 ((ViewGroup) shownPanelParent).removeView(st.shownPanelView);
803 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800804 st.decorView.addView(st.shownPanelView, lp);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800805
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800806 /*
807 * Give focus to the view, if it or one of its children does not
808 * already have it.
809 */
810 if (!st.shownPanelView.hasFocus()) {
811 st.shownPanelView.requestFocus();
812 }
Adam Powelldfee59a2011-08-05 20:48:30 -0700813 } else if (!st.isInListMode()) {
Adam Powelldc5facd2011-08-03 16:45:45 -0700814 width = MATCH_PARENT;
Adam Powell3429ff52011-08-18 18:32:48 -0700815 } else if (st.createdPanelView != null) {
816 // If we already had a panel view, carry width=MATCH_PARENT through
817 // as we did above when it was created.
818 ViewGroup.LayoutParams lp = st.createdPanelView.getLayoutParams();
819 if (lp != null && lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
820 width = MATCH_PARENT;
821 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800822 }
823
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800824 st.isHandled = false;
825
826 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
Adam Powella3e3c532011-06-22 11:21:54 -0700827 width, WRAP_CONTENT,
Dianne Hackbornd3715102009-09-15 19:28:03 -0700828 st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG,
Jeff Brown3cc321e2012-07-16 16:04:23 -0700829 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
Jeff Brown46e75292010-11-10 16:53:45 -0800830 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800831 st.decorView.mDefaultOpacity);
832
Adam Powelldfee59a2011-08-05 20:48:30 -0700833 if (st.isCompact) {
834 lp.gravity = getOptionsPanelGravity();
835 sRotationWatcher.addWindow(this);
836 } else {
837 lp.gravity = st.gravity;
838 }
839
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800840 lp.windowAnimations = st.windowAnimations;
Craig Mautner9b407282013-07-01 12:57:51 -0700841
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800842 wm.addView(st.decorView, lp);
Craig Mautner9b407282013-07-01 12:57:51 -0700843 st.isOpen = true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800844 // Log.v(TAG, "Adding main menu to window manager.");
845 }
846
847 @Override
848 public final void closePanel(int featureId) {
Adam Powell4369e7d2014-05-17 14:16:08 -0700849 if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
850 mDecorContentParent.canShowOverflowMenu() &&
Adam Powell5fcf5b92013-09-11 08:45:36 -0700851 !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
Adam Powell4369e7d2014-05-17 14:16:08 -0700852 mDecorContentParent.hideOverflowMenu();
Adam Powellf75eeb22010-08-10 15:59:40 -0700853 } else if (featureId == FEATURE_CONTEXT_MENU) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800854 closeContextMenu();
855 } else {
856 closePanel(getPanelState(featureId, true), true);
857 }
858 }
859
860 /**
861 * Closes the given panel.
862 *
863 * @param st The panel to be closed.
864 * @param doCallback Whether to notify the callback that the panel was
865 * closed. If the panel is in the process of re-opening or
866 * opening another panel (e.g., menu opening a sub menu), the
867 * callback should not happen and this variable should be false.
868 * In addition, this method internally will only perform the
869 * callback if the panel is open.
870 */
871 public final void closePanel(PanelFeatureState st, boolean doCallback) {
872 // System.out.println("Close panel: isOpen=" + st.isOpen);
Adam Powell696cba52011-03-29 10:38:16 -0700873 if (doCallback && st.featureId == FEATURE_OPTIONS_PANEL &&
Adam Powell4369e7d2014-05-17 14:16:08 -0700874 mDecorContentParent != null && mDecorContentParent.isOverflowMenuShowing()) {
Adam Powell696cba52011-03-29 10:38:16 -0700875 checkCloseActionMenu(st.menu);
876 return;
877 }
878
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800879 final ViewManager wm = getWindowManager();
880 if ((wm != null) && st.isOpen) {
881 if (st.decorView != null) {
882 wm.removeView(st.decorView);
883 // Log.v(TAG, "Removing main menu from window manager.");
Adam Powelldfee59a2011-08-05 20:48:30 -0700884 if (st.isCompact) {
885 sRotationWatcher.removeWindow(this);
886 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800887 }
888
889 if (doCallback) {
890 callOnPanelClosed(st.featureId, st, null);
891 }
892 }
Adam Powell696cba52011-03-29 10:38:16 -0700893
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800894 st.isPrepared = false;
895 st.isHandled = false;
896 st.isOpen = false;
897
898 // This view is no longer shown, so null it out
899 st.shownPanelView = null;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800900
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800901 if (st.isInExpandedMode) {
902 // Next time the menu opens, it should not be in expanded mode, so
903 // force a refresh of the decor
904 st.refreshDecorView = true;
905 st.isInExpandedMode = false;
906 }
907
908 if (mPreparedPanel == st) {
909 mPreparedPanel = null;
910 mPanelChordingKey = 0;
911 }
912 }
913
Adam Powell640a66e2011-04-29 10:18:53 -0700914 void checkCloseActionMenu(Menu menu) {
Adam Powell8515ee82010-11-30 14:09:55 -0800915 if (mClosingActionMenu) {
916 return;
917 }
918
Adam Powell8515ee82010-11-30 14:09:55 -0800919 mClosingActionMenu = true;
Adam Powell4369e7d2014-05-17 14:16:08 -0700920 mDecorContentParent.dismissPopups();
Adam Powell8515ee82010-11-30 14:09:55 -0800921 Callback cb = getCallback();
Adam Powell696cba52011-03-29 10:38:16 -0700922 if (cb != null && !isDestroyed()) {
Adam Powell8515ee82010-11-30 14:09:55 -0800923 cb.onPanelClosed(FEATURE_ACTION_BAR, menu);
924 }
925 mClosingActionMenu = false;
926 }
927
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800928 @Override
929 public final void togglePanel(int featureId, KeyEvent event) {
930 PanelFeatureState st = getPanelState(featureId, true);
931 if (st.isOpen) {
932 closePanel(st, true);
933 } else {
934 openPanel(st, event);
935 }
936 }
937
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700938 @Override
939 public void invalidatePanelMenu(int featureId) {
Adam Powell4b6d93f2012-09-18 18:34:08 -0700940 mInvalidatePanelMenuFeatures |= 1 << featureId;
941
942 if (!mInvalidatePanelMenuPosted && mDecor != null) {
943 mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
944 mInvalidatePanelMenuPosted = true;
945 }
946 }
947
Adam Powell31c91c82014-08-22 17:20:00 -0700948 void doPendingInvalidatePanelMenu() {
949 if (mInvalidatePanelMenuPosted) {
950 mDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
951 mInvalidatePanelMenuRunnable.run();
952 }
953 }
954
Adam Powell4b6d93f2012-09-18 18:34:08 -0700955 void doInvalidatePanelMenu(int featureId) {
Jose Lima7a22fc62015-01-23 17:24:22 -0800956 PanelFeatureState st = getPanelState(featureId, false);
957 if (st == null) {
958 return;
959 }
Adam Powell038f1c82011-07-21 14:28:10 -0700960 Bundle savedActionViewStates = null;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700961 if (st.menu != null) {
Adam Powell038f1c82011-07-21 14:28:10 -0700962 savedActionViewStates = new Bundle();
963 st.menu.saveActionViewStates(savedActionViewStates);
964 if (savedActionViewStates.size() > 0) {
965 st.frozenActionViewState = savedActionViewStates;
966 }
Adam Powell89b09da2011-07-27 11:55:29 -0700967 // This will be started again when the panel is prepared.
968 st.menu.stopDispatchingItemsChanged();
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700969 st.menu.clear();
970 }
971 st.refreshMenuContent = true;
972 st.refreshDecorView = true;
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700973
Adam Powell96675b12010-06-10 18:58:59 -0700974 // Prepare the options panel if we have an action bar
975 if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL)
Adam Powell4369e7d2014-05-17 14:16:08 -0700976 && mDecorContentParent != null) {
Adam Powell96675b12010-06-10 18:58:59 -0700977 st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
978 if (st != null) {
979 st.isPrepared = false;
980 preparePanel(st, null);
981 }
982 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700983 }
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700984
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800985 /**
986 * Called when the panel key is pushed down.
987 * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
988 * @param event The key event.
989 * @return Whether the key was handled.
990 */
991 public final boolean onKeyDownPanel(int featureId, KeyEvent event) {
Dianne Hackborna207baa2009-09-13 16:14:44 -0700992 final int keyCode = event.getKeyCode();
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700993
Dianne Hackborna207baa2009-09-13 16:14:44 -0700994 if (event.getRepeatCount() == 0) {
995 // The panel key was pushed, so set the chording key
996 mPanelChordingKey = keyCode;
Adam Powellf6148c52010-08-11 21:10:16 -0700997
Jose Lima7a22fc62015-01-23 17:24:22 -0800998 PanelFeatureState st = getPanelState(featureId, false);
999 if (st != null && !st.isOpen) {
Dianne Hackborna207baa2009-09-13 16:14:44 -07001000 return preparePanel(st, event);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001001 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001002 }
1003
1004 return false;
1005 }
1006
1007 /**
1008 * Called when the panel key is released.
1009 * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
1010 * @param event The key event.
1011 */
1012 public final void onKeyUpPanel(int featureId, KeyEvent event) {
1013 // The panel key was released, so clear the chording key
1014 if (mPanelChordingKey != 0) {
1015 mPanelChordingKey = 0;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001016
Jose Lima7a22fc62015-01-23 17:24:22 -08001017 final PanelFeatureState st = getPanelState(featureId, false);
1018
Clara Bayarri80c38562015-03-04 17:10:57 +00001019 if (event.isCanceled() || (mDecor != null && mDecor.mPrimaryActionMode != null) ||
Jose Lima7a22fc62015-01-23 17:24:22 -08001020 (st == null)) {
Dianne Hackborn0041e972009-07-24 17:14:43 -07001021 return;
1022 }
Alan Viveretteeb1d3792014-06-03 18:36:03 -07001023
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001024 boolean playSoundEffect = false;
Adam Powell4369e7d2014-05-17 14:16:08 -07001025 if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
1026 mDecorContentParent.canShowOverflowMenu() &&
Adam Powell5fcf5b92013-09-11 08:45:36 -07001027 !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
Adam Powell4369e7d2014-05-17 14:16:08 -07001028 if (!mDecorContentParent.isOverflowMenuShowing()) {
1029 if (!isDestroyed() && preparePanel(st, event)) {
1030 playSoundEffect = mDecorContentParent.showOverflowMenu();
Adam Powellf6148c52010-08-11 21:10:16 -07001031 }
Adam Powell4369e7d2014-05-17 14:16:08 -07001032 } else {
1033 playSoundEffect = mDecorContentParent.hideOverflowMenu();
Adam Powellf6148c52010-08-11 21:10:16 -07001034 }
1035 } else {
1036 if (st.isOpen || st.isHandled) {
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001037
Adam Powellf6148c52010-08-11 21:10:16 -07001038 // Play the sound effect if the user closed an open menu (and not if
1039 // they just released a menu shortcut)
1040 playSoundEffect = st.isOpen;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001041
Adam Powellf6148c52010-08-11 21:10:16 -07001042 // Close menu
1043 closePanel(st, true);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001044
Adam Powellf6148c52010-08-11 21:10:16 -07001045 } else if (st.isPrepared) {
Adam Powellc6d51882011-10-13 11:33:24 -07001046 boolean show = true;
1047 if (st.refreshMenuContent) {
1048 // Something may have invalidated the menu since we prepared it.
1049 // Re-prepare it to refresh.
1050 st.isPrepared = false;
1051 show = preparePanel(st, event);
1052 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001053
Adam Powellc6d51882011-10-13 11:33:24 -07001054 if (show) {
1055 // Write 'menu opened' to event log
1056 EventLog.writeEvent(50001, 0);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001057
Adam Powellc6d51882011-10-13 11:33:24 -07001058 // Show menu
1059 openPanel(st, event);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001060
Adam Powellc6d51882011-10-13 11:33:24 -07001061 playSoundEffect = true;
1062 }
Adam Powellf6148c52010-08-11 21:10:16 -07001063 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001064 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001065
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001066 if (playSoundEffect) {
1067 AudioManager audioManager = (AudioManager) getContext().getSystemService(
1068 Context.AUDIO_SERVICE);
1069 if (audioManager != null) {
1070 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
1071 } else {
1072 Log.w(TAG, "Couldn't get audio manager");
1073 }
1074 }
1075 }
1076 }
1077
1078 @Override
1079 public final void closeAllPanels() {
1080 final ViewManager wm = getWindowManager();
1081 if (wm == null) {
1082 return;
1083 }
1084
1085 final PanelFeatureState[] panels = mPanels;
1086 final int N = panels != null ? panels.length : 0;
1087 for (int i = 0; i < N; i++) {
1088 final PanelFeatureState panel = panels[i];
1089 if (panel != null) {
1090 closePanel(panel, true);
1091 }
1092 }
1093
1094 closeContextMenu();
1095 }
1096
1097 /**
1098 * Closes the context menu. This notifies the menu logic of the close, along
1099 * with dismissing it from the UI.
1100 */
1101 private synchronized void closeContextMenu() {
1102 if (mContextMenu != null) {
1103 mContextMenu.close();
1104 dismissContextMenu();
1105 }
1106 }
1107
1108 /**
1109 * Dismisses just the context menu UI. To close the context menu, use
1110 * {@link #closeContextMenu()}.
1111 */
1112 private synchronized void dismissContextMenu() {
1113 mContextMenu = null;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001114
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001115 if (mContextMenuHelper != null) {
1116 mContextMenuHelper.dismiss();
1117 mContextMenuHelper = null;
1118 }
1119 }
1120
1121 @Override
1122 public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
Jose Lima7a22fc62015-01-23 17:24:22 -08001123 return performPanelShortcut(getPanelState(featureId, false), keyCode, event, flags);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001124 }
1125
Wale Ogunwale8804af22015-11-17 09:18:15 -08001126 boolean performPanelShortcut(PanelFeatureState st, int keyCode, KeyEvent event,
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001127 int flags) {
1128 if (event.isSystem() || (st == null)) {
1129 return false;
1130 }
1131
1132 boolean handled = false;
1133
1134 // Only try to perform menu shortcuts if preparePanel returned true (possible false
1135 // return value from application not wanting to show the menu).
1136 if ((st.isPrepared || preparePanel(st, event)) && st.menu != null) {
1137 // The menu is prepared now, perform the shortcut on it
1138 handled = st.menu.performShortcut(keyCode, event, flags);
1139 }
1140
1141 if (handled) {
1142 // Mark as handled
1143 st.isHandled = true;
1144
Adam Powell6055f3e2011-08-28 14:20:24 -07001145 // Only close down the menu if we don't have an action bar keeping it open.
Adam Powell4369e7d2014-05-17 14:16:08 -07001146 if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0 && mDecorContentParent == null) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001147 closePanel(st, true);
1148 }
1149 }
1150
1151 return handled;
1152 }
1153
1154 @Override
1155 public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
1156
1157 PanelFeatureState st = getPanelState(featureId, true);
1158 if (!preparePanel(st, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU))) {
1159 return false;
1160 }
1161 if (st.menu == null) {
1162 return false;
1163 }
1164
1165 boolean res = st.menu.performIdentifierAction(id, flags);
1166
Adam Powell6055f3e2011-08-28 14:20:24 -07001167 // Only close down the menu if we don't have an action bar keeping it open.
Adam Powell4369e7d2014-05-17 14:16:08 -07001168 if (mDecorContentParent == null) {
Adam Powell6055f3e2011-08-28 14:20:24 -07001169 closePanel(st, true);
1170 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001171
1172 return res;
1173 }
1174
1175 public PanelFeatureState findMenuPanel(Menu menu) {
1176 final PanelFeatureState[] panels = mPanels;
1177 final int N = panels != null ? panels.length : 0;
1178 for (int i = 0; i < N; i++) {
1179 final PanelFeatureState panel = panels[i];
1180 if (panel != null && panel.menu == menu) {
1181 return panel;
1182 }
1183 }
1184 return null;
1185 }
1186
1187 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
1188 final Callback cb = getCallback();
Dianne Hackbornb66ad572011-03-01 17:10:30 -08001189 if (cb != null && !isDestroyed()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001190 final PanelFeatureState panel = findMenuPanel(menu.getRootMenu());
1191 if (panel != null) {
1192 return cb.onMenuItemSelected(panel.featureId, item);
1193 }
1194 }
1195 return false;
1196 }
1197
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001198 public void onMenuModeChange(MenuBuilder menu) {
1199 reopenMenu(true);
1200 }
1201
1202 private void reopenMenu(boolean toggleMenuMode) {
Adam Powell4369e7d2014-05-17 14:16:08 -07001203 if (mDecorContentParent != null && mDecorContentParent.canShowOverflowMenu() &&
Adam Powell5fcf5b92013-09-11 08:45:36 -07001204 (!ViewConfiguration.get(getContext()).hasPermanentMenuKey() ||
Adam Powell4369e7d2014-05-17 14:16:08 -07001205 mDecorContentParent.isOverflowMenuShowPending())) {
Adam Powell8515ee82010-11-30 14:09:55 -08001206 final Callback cb = getCallback();
Adam Powell4369e7d2014-05-17 14:16:08 -07001207 if (!mDecorContentParent.isOverflowMenuShowing() || !toggleMenuMode) {
1208 if (cb != null && !isDestroyed()) {
Adam Powell5c8f9b52013-03-27 12:22:27 -07001209 // If we have a menu invalidation pending, do it now.
1210 if (mInvalidatePanelMenuPosted &&
1211 (mInvalidatePanelMenuFeatures & (1 << FEATURE_OPTIONS_PANEL)) != 0) {
1212 mDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
1213 mInvalidatePanelMenuRunnable.run();
1214 }
1215
Jose Lima7a22fc62015-01-23 17:24:22 -08001216 final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
Adam Powell6a5b0a32012-09-28 14:24:48 -07001217
1218 // If we don't have a menu or we're waiting for a full content refresh,
1219 // forget it. This is a lingering event that no longer matters.
Jose Lima7a22fc62015-01-23 17:24:22 -08001220 if (st != null && st.menu != null && !st.refreshMenuContent &&
Adam Powell6a5b0a32012-09-28 14:24:48 -07001221 cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
Adam Powell8515ee82010-11-30 14:09:55 -08001222 cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
Adam Powell4369e7d2014-05-17 14:16:08 -07001223 mDecorContentParent.showOverflowMenu();
Adam Powellf6148c52010-08-11 21:10:16 -07001224 }
1225 }
1226 } else {
Adam Powell4369e7d2014-05-17 14:16:08 -07001227 mDecorContentParent.hideOverflowMenu();
Jose Lima7a22fc62015-01-23 17:24:22 -08001228 final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
1229 if (st != null && cb != null && !isDestroyed()) {
Adam Powell8515ee82010-11-30 14:09:55 -08001230 cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu);
1231 }
Adam Powellf6148c52010-08-11 21:10:16 -07001232 }
1233 return;
1234 }
1235
Jose Lima7a22fc62015-01-23 17:24:22 -08001236 PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
1237
1238 if (st == null) {
1239 return;
1240 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001241
1242 // Save the future expanded mode state since closePanel will reset it
1243 boolean newExpandedMode = toggleMenuMode ? !st.isInExpandedMode : st.isInExpandedMode;
1244
1245 st.refreshDecorView = true;
1246 closePanel(st, false);
1247
1248 // Set the expanded mode state
1249 st.isInExpandedMode = newExpandedMode;
1250
1251 openPanel(st, null);
1252 }
1253
1254 /**
1255 * Initializes the menu associated with the given panel feature state. You
1256 * must at the very least set PanelFeatureState.menu to the Menu to be
1257 * associated with the given panel state. The default implementation creates
1258 * a new menu for the panel state.
1259 *
1260 * @param st The panel whose menu is being initialized.
1261 * @return Whether the initialization was successful.
1262 */
1263 protected boolean initializePanelMenu(final PanelFeatureState st) {
Adam Powelld65b3b92011-09-22 16:38:11 -07001264 Context context = getContext();
1265
Alan Viveretteeb1d3792014-06-03 18:36:03 -07001266 // If we have an action bar, initialize the menu with the right theme.
Adam Powelld65b3b92011-09-22 16:38:11 -07001267 if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR) &&
Adam Powell4369e7d2014-05-17 14:16:08 -07001268 mDecorContentParent != null) {
Alan Viverette4b002d32014-06-03 17:32:19 -07001269 final TypedValue outValue = new TypedValue();
1270 final Theme baseTheme = context.getTheme();
Alan Viverette40982d42014-07-25 17:48:55 -07001271 baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
Adam Powelld65b3b92011-09-22 16:38:11 -07001272
Alan Viverette4b002d32014-06-03 17:32:19 -07001273 Theme widgetTheme = null;
1274 if (outValue.resourceId != 0) {
1275 widgetTheme = context.getResources().newTheme();
1276 widgetTheme.setTo(baseTheme);
1277 widgetTheme.applyStyle(outValue.resourceId, true);
1278 widgetTheme.resolveAttribute(
Alan Viverette40982d42014-07-25 17:48:55 -07001279 R.attr.actionBarWidgetTheme, outValue, true);
Alan Viverette4b002d32014-06-03 17:32:19 -07001280 } else {
1281 baseTheme.resolveAttribute(
Alan Viverette40982d42014-07-25 17:48:55 -07001282 R.attr.actionBarWidgetTheme, outValue, true);
Alan Viverette4b002d32014-06-03 17:32:19 -07001283 }
1284
1285 if (outValue.resourceId != 0) {
1286 if (widgetTheme == null) {
1287 widgetTheme = context.getResources().newTheme();
1288 widgetTheme.setTo(baseTheme);
1289 }
1290 widgetTheme.applyStyle(outValue.resourceId, true);
1291 }
1292
1293 if (widgetTheme != null) {
1294 context = new ContextThemeWrapper(context, 0);
1295 context.getTheme().setTo(widgetTheme);
Adam Powelld65b3b92011-09-22 16:38:11 -07001296 }
1297 }
1298
1299 final MenuBuilder menu = new MenuBuilder(context);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001300 menu.setCallback(this);
1301 st.setMenu(menu);
1302
1303 return true;
1304 }
1305
1306 /**
1307 * Perform initial setup of a panel. This should at the very least set the
1308 * style information in the PanelFeatureState and must set
1309 * PanelFeatureState.decor to the panel's window decor view.
1310 *
1311 * @param st The panel being initialized.
1312 */
1313 protected boolean initializePanelDecor(PanelFeatureState st) {
Stefan Kuhne61b47bb2015-07-28 14:04:25 -07001314 st.decorView = generateDecor(st.featureId);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001315 st.gravity = Gravity.CENTER | Gravity.BOTTOM;
1316 st.setStyle(getContext());
Adam Powell594558d2014-09-18 18:22:29 -07001317 TypedArray a = getContext().obtainStyledAttributes(null,
1318 R.styleable.Window, 0, st.listPresenterTheme);
1319 final float elevation = a.getDimension(R.styleable.Window_windowElevation, 0);
1320 if (elevation != 0) {
1321 st.decorView.setElevation(elevation);
1322 }
1323 a.recycle();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001324
1325 return true;
1326 }
1327
1328 /**
Adam Powelldfee59a2011-08-05 20:48:30 -07001329 * Determine the gravity value for the options panel. This can
1330 * differ in compact mode.
1331 *
1332 * @return gravity value to use for the panel window
1333 */
1334 private int getOptionsPanelGravity() {
1335 try {
1336 return WindowManagerHolder.sWindowManager.getPreferredOptionsPanelGravity();
1337 } catch (RemoteException ex) {
1338 Log.e(TAG, "Couldn't getOptionsPanelGravity; using default", ex);
1339 return Gravity.CENTER | Gravity.BOTTOM;
1340 }
1341 }
1342
1343 void onOptionsPanelRotationChanged() {
1344 final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
1345 if (st == null) return;
1346
1347 final WindowManager.LayoutParams lp = st.decorView != null ?
1348 (WindowManager.LayoutParams) st.decorView.getLayoutParams() : null;
1349 if (lp != null) {
1350 lp.gravity = getOptionsPanelGravity();
1351 final ViewManager wm = getWindowManager();
1352 if (wm != null) {
1353 wm.updateViewLayout(st.decorView, lp);
1354 }
1355 }
1356 }
1357
1358 /**
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001359 * Initializes the panel associated with the panel feature state. You must
1360 * at the very least set PanelFeatureState.panel to the View implementing
1361 * its contents. The default implementation gets the panel from the menu.
1362 *
1363 * @param st The panel state being initialized.
1364 * @return Whether the initialization was successful.
1365 */
1366 protected boolean initializePanelContent(PanelFeatureState st) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001367 if (st.createdPanelView != null) {
1368 st.shownPanelView = st.createdPanelView;
1369 return true;
1370 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001371
Adam Powell696cba52011-03-29 10:38:16 -07001372 if (st.menu == null) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001373 return false;
1374 }
1375
Adam Powell696cba52011-03-29 10:38:16 -07001376 if (mPanelMenuPresenterCallback == null) {
1377 mPanelMenuPresenterCallback = new PanelMenuPresenterCallback();
1378 }
1379
Adam Powelldfee59a2011-08-05 20:48:30 -07001380 MenuView menuView = st.isInListMode()
Adam Powell538e5652011-10-11 13:47:08 -07001381 ? st.getListMenuView(getContext(), mPanelMenuPresenterCallback)
1382 : st.getIconMenuView(getContext(), mPanelMenuPresenterCallback);
Adam Powell696cba52011-03-29 10:38:16 -07001383
1384 st.shownPanelView = (View) menuView;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001385
1386 if (st.shownPanelView != null) {
1387 // Use the menu View's default animations if it has any
Adam Powell696cba52011-03-29 10:38:16 -07001388 final int defaultAnimations = menuView.getWindowAnimations();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001389 if (defaultAnimations != 0) {
1390 st.windowAnimations = defaultAnimations;
1391 }
1392 return true;
1393 } else {
1394 return false;
1395 }
1396 }
1397
1398 @Override
1399 public boolean performContextMenuIdentifierAction(int id, int flags) {
1400 return (mContextMenu != null) ? mContextMenu.performIdentifierAction(id, flags) : false;
1401 }
1402
1403 @Override
Alan Viverette79c067c52014-10-29 14:27:47 -07001404 public final void setElevation(float elevation) {
1405 mElevation = elevation;
1406 if (mDecor != null) {
1407 mDecor.setElevation(elevation);
1408 }
Alan Viverette71922de2015-01-12 16:14:02 -08001409 dispatchWindowAttributesChanged(getAttributes());
Alan Viverette79c067c52014-10-29 14:27:47 -07001410 }
1411
1412 @Override
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -07001413 public float getElevation() {
1414 return mElevation;
1415 }
1416
1417 @Override
Alan Viverette79c067c52014-10-29 14:27:47 -07001418 public final void setClipToOutline(boolean clipToOutline) {
1419 mClipToOutline = clipToOutline;
1420 if (mDecor != null) {
1421 mDecor.setClipToOutline(clipToOutline);
1422 }
1423 }
1424
1425 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001426 public final void setBackgroundDrawable(Drawable drawable) {
Dianne Hackborna7c176c2009-06-22 20:56:57 -07001427 if (drawable != mBackgroundDrawable || mBackgroundResource != 0) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001428 mBackgroundResource = 0;
1429 mBackgroundDrawable = drawable;
1430 if (mDecor != null) {
1431 mDecor.setWindowBackground(drawable);
1432 }
Adam Powellf849a5e2014-09-11 15:09:36 -07001433 if (mBackgroundFallbackResource != 0) {
1434 mDecor.setBackgroundFallback(drawable != null ? 0 : mBackgroundFallbackResource);
1435 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001436 }
1437 }
1438
1439 @Override
1440 public final void setFeatureDrawableResource(int featureId, int resId) {
1441 if (resId != 0) {
1442 DrawableFeatureState st = getDrawableState(featureId, true);
1443 if (st.resid != resId) {
1444 st.resid = resId;
1445 st.uri = null;
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001446 st.local = getContext().getDrawable(resId);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001447 updateDrawable(featureId, st, false);
1448 }
1449 } else {
1450 setFeatureDrawable(featureId, null);
1451 }
1452 }
1453
1454 @Override
1455 public final void setFeatureDrawableUri(int featureId, Uri uri) {
1456 if (uri != null) {
1457 DrawableFeatureState st = getDrawableState(featureId, true);
1458 if (st.uri == null || !st.uri.equals(uri)) {
1459 st.resid = 0;
1460 st.uri = uri;
1461 st.local = loadImageURI(uri);
1462 updateDrawable(featureId, st, false);
1463 }
1464 } else {
1465 setFeatureDrawable(featureId, null);
1466 }
1467 }
1468
1469 @Override
1470 public final void setFeatureDrawable(int featureId, Drawable drawable) {
1471 DrawableFeatureState st = getDrawableState(featureId, true);
1472 st.resid = 0;
1473 st.uri = null;
1474 if (st.local != drawable) {
1475 st.local = drawable;
1476 updateDrawable(featureId, st, false);
1477 }
1478 }
1479
1480 @Override
1481 public void setFeatureDrawableAlpha(int featureId, int alpha) {
1482 DrawableFeatureState st = getDrawableState(featureId, true);
1483 if (st.alpha != alpha) {
1484 st.alpha = alpha;
1485 updateDrawable(featureId, st, false);
1486 }
1487 }
1488
1489 protected final void setFeatureDefaultDrawable(int featureId, Drawable drawable) {
1490 DrawableFeatureState st = getDrawableState(featureId, true);
1491 if (st.def != drawable) {
1492 st.def = drawable;
1493 updateDrawable(featureId, st, false);
1494 }
1495 }
1496
1497 @Override
1498 public final void setFeatureInt(int featureId, int value) {
1499 // XXX Should do more management (as with drawable features) to
1500 // deal with interactions between multiple window policies.
1501 updateInt(featureId, value, false);
1502 }
1503
1504 /**
1505 * Update the state of a drawable feature. This should be called, for every
1506 * drawable feature supported, as part of onActive(), to make sure that the
1507 * contents of a containing window is properly updated.
1508 *
1509 * @see #onActive
1510 * @param featureId The desired drawable feature to change.
1511 * @param fromActive Always true when called from onActive().
1512 */
1513 protected final void updateDrawable(int featureId, boolean fromActive) {
1514 final DrawableFeatureState st = getDrawableState(featureId, false);
1515 if (st != null) {
1516 updateDrawable(featureId, st, fromActive);
1517 }
1518 }
1519
1520 /**
1521 * Called when a Drawable feature changes, for the window to update its
1522 * graphics.
1523 *
1524 * @param featureId The feature being changed.
1525 * @param drawable The new Drawable to show, or null if none.
1526 * @param alpha The new alpha blending of the Drawable.
1527 */
1528 protected void onDrawableChanged(int featureId, Drawable drawable, int alpha) {
1529 ImageView view;
1530 if (featureId == FEATURE_LEFT_ICON) {
1531 view = getLeftIconView();
1532 } else if (featureId == FEATURE_RIGHT_ICON) {
1533 view = getRightIconView();
1534 } else {
1535 return;
1536 }
1537
1538 if (drawable != null) {
1539 drawable.setAlpha(alpha);
1540 view.setImageDrawable(drawable);
1541 view.setVisibility(View.VISIBLE);
1542 } else {
1543 view.setVisibility(View.GONE);
1544 }
1545 }
1546
1547 /**
1548 * Called when an int feature changes, for the window to update its
1549 * graphics.
1550 *
1551 * @param featureId The feature being changed.
1552 * @param value The new integer value.
1553 */
1554 protected void onIntChanged(int featureId, int value) {
1555 if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) {
1556 updateProgressBars(value);
1557 } else if (featureId == FEATURE_CUSTOM_TITLE) {
Alan Viverette40982d42014-07-25 17:48:55 -07001558 FrameLayout titleContainer = (FrameLayout) findViewById(R.id.title_container);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001559 if (titleContainer != null) {
1560 mLayoutInflater.inflate(value, titleContainer);
1561 }
1562 }
1563 }
1564
1565 /**
1566 * Updates the progress bars that are shown in the title bar.
1567 *
1568 * @param value Can be one of {@link Window#PROGRESS_VISIBILITY_ON},
1569 * {@link Window#PROGRESS_VISIBILITY_OFF},
1570 * {@link Window#PROGRESS_INDETERMINATE_ON},
1571 * {@link Window#PROGRESS_INDETERMINATE_OFF}, or a value
1572 * starting at {@link Window#PROGRESS_START} through
1573 * {@link Window#PROGRESS_END} for setting the default
1574 * progress (if {@link Window#PROGRESS_END} is given,
1575 * the progress bar widgets in the title will be hidden after an
1576 * animation), a value between
1577 * {@link Window#PROGRESS_SECONDARY_START} -
1578 * {@link Window#PROGRESS_SECONDARY_END} for the
1579 * secondary progress (if
1580 * {@link Window#PROGRESS_SECONDARY_END} is given, the
1581 * progress bar widgets will still be shown with the secondary
1582 * progress bar will be completely filled in.)
1583 */
1584 private void updateProgressBars(int value) {
1585 ProgressBar circularProgressBar = getCircularProgressBar(true);
1586 ProgressBar horizontalProgressBar = getHorizontalProgressBar(true);
1587
1588 final int features = getLocalFeatures();
1589 if (value == PROGRESS_VISIBILITY_ON) {
1590 if ((features & (1 << FEATURE_PROGRESS)) != 0) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001591 if (horizontalProgressBar != null) {
1592 int level = horizontalProgressBar.getProgress();
1593 int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ?
1594 View.VISIBLE : View.INVISIBLE;
1595 horizontalProgressBar.setVisibility(visibility);
1596 } else {
1597 Log.e(TAG, "Horizontal progress bar not located in current window decor");
1598 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001599 }
1600 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001601 if (circularProgressBar != null) {
1602 circularProgressBar.setVisibility(View.VISIBLE);
1603 } else {
1604 Log.e(TAG, "Circular progress bar not located in current window decor");
1605 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001606 }
1607 } else if (value == PROGRESS_VISIBILITY_OFF) {
1608 if ((features & (1 << FEATURE_PROGRESS)) != 0) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001609 if (horizontalProgressBar != null) {
1610 horizontalProgressBar.setVisibility(View.GONE);
1611 } else {
1612 Log.e(TAG, "Horizontal progress bar not located in current window decor");
1613 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001614 }
1615 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001616 if (circularProgressBar != null) {
1617 circularProgressBar.setVisibility(View.GONE);
1618 } else {
1619 Log.e(TAG, "Circular progress bar not located in current window decor");
1620 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001621 }
1622 } else if (value == PROGRESS_INDETERMINATE_ON) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001623 if (horizontalProgressBar != null) {
1624 horizontalProgressBar.setIndeterminate(true);
1625 } else {
1626 Log.e(TAG, "Horizontal progress bar not located in current window decor");
1627 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001628 } else if (value == PROGRESS_INDETERMINATE_OFF) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001629 if (horizontalProgressBar != null) {
1630 horizontalProgressBar.setIndeterminate(false);
1631 } else {
1632 Log.e(TAG, "Horizontal progress bar not located in current window decor");
1633 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001634 } else if (PROGRESS_START <= value && value <= PROGRESS_END) {
1635 // We want to set the progress value before testing for visibility
1636 // so that when the progress bar becomes visible again, it has the
1637 // correct level.
Adam Powelleec8f0c2014-05-30 11:00:00 -07001638 if (horizontalProgressBar != null) {
1639 horizontalProgressBar.setProgress(value - PROGRESS_START);
1640 } else {
1641 Log.e(TAG, "Horizontal progress bar not located in current window decor");
1642 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001643
1644 if (value < PROGRESS_END) {
1645 showProgressBars(horizontalProgressBar, circularProgressBar);
1646 } else {
1647 hideProgressBars(horizontalProgressBar, circularProgressBar);
1648 }
1649 } else if (PROGRESS_SECONDARY_START <= value && value <= PROGRESS_SECONDARY_END) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001650 if (horizontalProgressBar != null) {
1651 horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START);
1652 } else {
1653 Log.e(TAG, "Horizontal progress bar not located in current window decor");
1654 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001655
1656 showProgressBars(horizontalProgressBar, circularProgressBar);
1657 }
1658
1659 }
1660
1661 private void showProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
1662 final int features = getLocalFeatures();
1663 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
Adam Powelleec8f0c2014-05-30 11:00:00 -07001664 spinnyProgressBar != null && spinnyProgressBar.getVisibility() == View.INVISIBLE) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001665 spinnyProgressBar.setVisibility(View.VISIBLE);
1666 }
1667 // Only show the progress bars if the primary progress is not complete
Adam Powelleec8f0c2014-05-30 11:00:00 -07001668 if ((features & (1 << FEATURE_PROGRESS)) != 0 && horizontalProgressBar != null &&
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001669 horizontalProgressBar.getProgress() < 10000) {
1670 horizontalProgressBar.setVisibility(View.VISIBLE);
1671 }
1672 }
1673
1674 private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
1675 final int features = getLocalFeatures();
Alan Viverette40982d42014-07-25 17:48:55 -07001676 Animation anim = AnimationUtils.loadAnimation(getContext(), R.anim.fade_out);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001677 anim.setDuration(1000);
1678 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
Adam Powelleec8f0c2014-05-30 11:00:00 -07001679 spinnyProgressBar != null &&
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001680 spinnyProgressBar.getVisibility() == View.VISIBLE) {
1681 spinnyProgressBar.startAnimation(anim);
1682 spinnyProgressBar.setVisibility(View.INVISIBLE);
1683 }
Adam Powelleec8f0c2014-05-30 11:00:00 -07001684 if ((features & (1 << FEATURE_PROGRESS)) != 0 && horizontalProgressBar != null &&
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001685 horizontalProgressBar.getVisibility() == View.VISIBLE) {
1686 horizontalProgressBar.startAnimation(anim);
1687 horizontalProgressBar.setVisibility(View.INVISIBLE);
1688 }
1689 }
1690
Adam Powell04fe6eb2013-05-31 14:39:48 -07001691 @Override
1692 public void setIcon(int resId) {
1693 mIconRes = resId;
1694 mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON;
Adam Powell0a317e92013-06-13 13:15:43 -07001695 mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
Adam Powell4369e7d2014-05-17 14:16:08 -07001696 if (mDecorContentParent != null) {
1697 mDecorContentParent.setIcon(resId);
Adam Powell04fe6eb2013-05-31 14:39:48 -07001698 }
1699 }
1700
1701 @Override
1702 public void setDefaultIcon(int resId) {
1703 if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0) {
1704 return;
1705 }
1706 mIconRes = resId;
Adam Powell4369e7d2014-05-17 14:16:08 -07001707 if (mDecorContentParent != null && (!mDecorContentParent.hasIcon() ||
Adam Powell0a317e92013-06-13 13:15:43 -07001708 (mResourcesSetFlags & FLAG_RESOURCE_SET_ICON_FALLBACK) != 0)) {
1709 if (resId != 0) {
Adam Powell4369e7d2014-05-17 14:16:08 -07001710 mDecorContentParent.setIcon(resId);
Adam Powell0a317e92013-06-13 13:15:43 -07001711 mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
1712 } else {
Adam Powell4369e7d2014-05-17 14:16:08 -07001713 mDecorContentParent.setIcon(
1714 getContext().getPackageManager().getDefaultActivityIcon());
Adam Powell0a317e92013-06-13 13:15:43 -07001715 mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
1716 }
Adam Powell04fe6eb2013-05-31 14:39:48 -07001717 }
1718 }
1719
1720 @Override
1721 public void setLogo(int resId) {
1722 mLogoRes = resId;
1723 mResourcesSetFlags |= FLAG_RESOURCE_SET_LOGO;
Adam Powell4369e7d2014-05-17 14:16:08 -07001724 if (mDecorContentParent != null) {
1725 mDecorContentParent.setLogo(resId);
Adam Powell04fe6eb2013-05-31 14:39:48 -07001726 }
1727 }
1728
1729 @Override
1730 public void setDefaultLogo(int resId) {
1731 if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0) {
1732 return;
1733 }
1734 mLogoRes = resId;
Adam Powell4369e7d2014-05-17 14:16:08 -07001735 if (mDecorContentParent != null && !mDecorContentParent.hasLogo()) {
1736 mDecorContentParent.setLogo(resId);
Adam Powell04fe6eb2013-05-31 14:39:48 -07001737 }
1738 }
1739
keunyoung30f420f2013-08-02 14:23:10 -07001740 @Override
1741 public void setLocalFocus(boolean hasFocus, boolean inTouchMode) {
1742 getViewRootImpl().windowFocusChanged(hasFocus, inTouchMode);
1743
1744 }
1745
1746 @Override
1747 public void injectInputEvent(InputEvent event) {
1748 getViewRootImpl().dispatchInputEvent(event);
1749 }
1750
1751 private ViewRootImpl getViewRootImpl() {
1752 if (mDecor != null) {
1753 ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
1754 if (viewRootImpl != null) {
1755 return viewRootImpl;
1756 }
1757 }
1758 throw new IllegalStateException("view not added");
1759 }
1760
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001761 /**
1762 * Request that key events come to this activity. Use this if your activity
1763 * has no views with focus, but the activity still wants a chance to process
1764 * key events.
1765 */
1766 @Override
1767 public void takeKeyEvents(boolean get) {
1768 mDecor.setFocusable(get);
1769 }
1770
1771 @Override
1772 public boolean superDispatchKeyEvent(KeyEvent event) {
1773 return mDecor.superDispatchKeyEvent(event);
1774 }
1775
1776 @Override
Jeff Brown64da12a2011-01-04 19:57:47 -08001777 public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
1778 return mDecor.superDispatchKeyShortcutEvent(event);
1779 }
1780
1781 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001782 public boolean superDispatchTouchEvent(MotionEvent event) {
1783 return mDecor.superDispatchTouchEvent(event);
1784 }
1785
1786 @Override
1787 public boolean superDispatchTrackballEvent(MotionEvent event) {
1788 return mDecor.superDispatchTrackballEvent(event);
1789 }
1790
Jeff Browncb1404e2011-01-15 18:14:15 -08001791 @Override
1792 public boolean superDispatchGenericMotionEvent(MotionEvent event) {
1793 return mDecor.superDispatchGenericMotionEvent(event);
1794 }
1795
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001796 /**
1797 * A key was pressed down and not handled by anything else in the window.
1798 *
1799 * @see #onKeyUp
1800 * @see android.view.KeyEvent
1801 */
1802 protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
Joe Onorato86f67862010-11-05 18:57:34 -07001803 /* ****************************************************************************
1804 * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
1805 *
1806 * If your key handling must happen before the app gets a crack at the event,
1807 * it goes in PhoneWindowManager.
1808 *
1809 * If your key handling should happen in all windows, and does not depend on
1810 * the state of the current application, other than that the current
1811 * application can override the behavior by handling the event itself, it
1812 * should go in PhoneFallbackEventHandler.
1813 *
1814 * Only if your handling depends on the window, and the fact that it has
1815 * a DecorView, should it go here.
1816 * ****************************************************************************/
1817
Dianne Hackborna207baa2009-09-13 16:14:44 -07001818 final KeyEvent.DispatcherState dispatcher =
1819 mDecor != null ? mDecor.getKeyDispatcherState() : null;
1820 //Log.i(TAG, "Key down: repeat=" + event.getRepeatCount()
1821 // + " flags=0x" + Integer.toHexString(event.getFlags()));
Alan Viveretteeb1d3792014-06-03 18:36:03 -07001822
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001823 switch (keyCode) {
1824 case KeyEvent.KEYCODE_VOLUME_UP:
RoboErik5452e252015-02-06 15:33:53 -08001825 case KeyEvent.KEYCODE_VOLUME_DOWN:
1826 case KeyEvent.KEYCODE_VOLUME_MUTE: {
1827 int direction = 0;
1828 switch (keyCode) {
1829 case KeyEvent.KEYCODE_VOLUME_UP:
1830 direction = AudioManager.ADJUST_RAISE;
1831 break;
1832 case KeyEvent.KEYCODE_VOLUME_DOWN:
1833 direction = AudioManager.ADJUST_LOWER;
1834 break;
1835 case KeyEvent.KEYCODE_VOLUME_MUTE:
1836 direction = AudioManager.ADJUST_TOGGLE_MUTE;
1837 break;
1838 }
RoboErik55011652014-07-09 15:05:53 -07001839 // If we have a session send it the volume command, otherwise
1840 // use the suggested stream.
1841 if (mMediaController != null) {
RoboErik1ff5b162014-07-15 17:23:18 -07001842 mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);
RoboErik55011652014-07-09 15:05:53 -07001843 } else {
1844 MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
John Spurlock0635b892014-07-19 17:52:35 -04001845 mVolumeControlStreamType, direction,
John Spurlockb94f2d62015-03-17 14:11:57 -04001846 AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE
1847 | AudioManager.FLAG_FROM_KEY);
RoboErik55011652014-07-09 15:05:53 -07001848 }
1849 return true;
1850 }
RoboErik55011652014-07-09 15:05:53 -07001851 // These are all the recognized media key codes in
1852 // KeyEvent.isMediaKey()
1853 case KeyEvent.KEYCODE_MEDIA_PLAY:
1854 case KeyEvent.KEYCODE_MEDIA_PAUSE:
1855 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
1856 case KeyEvent.KEYCODE_MUTE:
1857 case KeyEvent.KEYCODE_HEADSETHOOK:
1858 case KeyEvent.KEYCODE_MEDIA_STOP:
1859 case KeyEvent.KEYCODE_MEDIA_NEXT:
1860 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
1861 case KeyEvent.KEYCODE_MEDIA_REWIND:
1862 case KeyEvent.KEYCODE_MEDIA_RECORD:
1863 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
1864 if (mMediaController != null) {
1865 if (mMediaController.dispatchMediaButtonEvent(event)) {
1866 return true;
1867 }
1868 }
RoboErik28204a72014-07-17 12:17:27 -07001869 return false;
RoboErik55011652014-07-09 15:05:53 -07001870 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001871
1872 case KeyEvent.KEYCODE_MENU: {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001873 onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
1874 return true;
1875 }
1876
1877 case KeyEvent.KEYCODE_BACK: {
1878 if (event.getRepeatCount() > 0) break;
1879 if (featureId < 0) break;
Dianne Hackbornfed9cb52009-09-14 21:23:11 -07001880 // Currently don't do anything with long press.
Winson Chung45d378b2011-09-08 19:02:06 -07001881 if (dispatcher != null) {
1882 dispatcher.startTracking(event, this);
1883 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001884 return true;
1885 }
1886
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001887 }
1888
1889 return false;
1890 }
1891
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001892 private KeyguardManager getKeyguardManager() {
1893 if (mKeyguardManager == null) {
Joe Onorato86f67862010-11-05 18:57:34 -07001894 mKeyguardManager = (KeyguardManager) getContext().getSystemService(
1895 Context.KEYGUARD_SERVICE);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001896 }
1897 return mKeyguardManager;
1898 }
Joe Onorato86f67862010-11-05 18:57:34 -07001899
1900 AudioManager getAudioManager() {
1901 if (mAudioManager == null) {
1902 mAudioManager = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
Mike LeBeaubfd25ca2010-03-22 17:40:35 -07001903 }
Joe Onorato86f67862010-11-05 18:57:34 -07001904 return mAudioManager;
Mike LeBeaubfd25ca2010-03-22 17:40:35 -07001905 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001906
1907 /**
1908 * A key was released and not handled by anything else in the window.
1909 *
1910 * @see #onKeyDown
1911 * @see android.view.KeyEvent
1912 */
1913 protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) {
Dianne Hackborna207baa2009-09-13 16:14:44 -07001914 final KeyEvent.DispatcherState dispatcher =
1915 mDecor != null ? mDecor.getKeyDispatcherState() : null;
1916 if (dispatcher != null) {
1917 dispatcher.handleUpEvent(event);
1918 }
1919 //Log.i(TAG, "Key up: repeat=" + event.getRepeatCount()
1920 // + " flags=0x" + Integer.toHexString(event.getFlags()));
Alan Viveretteeb1d3792014-06-03 18:36:03 -07001921
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001922 switch (keyCode) {
1923 case KeyEvent.KEYCODE_VOLUME_UP:
RoboErik55011652014-07-09 15:05:53 -07001924 case KeyEvent.KEYCODE_VOLUME_DOWN: {
John Spurlockb94f2d62015-03-17 14:11:57 -04001925 final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
1926 | AudioManager.FLAG_FROM_KEY;
RoboErik55011652014-07-09 15:05:53 -07001927 // If we have a session send it the volume command, otherwise
1928 // use the suggested stream.
1929 if (mMediaController != null) {
John Spurlockb94f2d62015-03-17 14:11:57 -04001930 mMediaController.adjustVolume(0, flags);
RoboErik55011652014-07-09 15:05:53 -07001931 } else {
1932 MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
John Spurlockb94f2d62015-03-17 14:11:57 -04001933 mVolumeControlStreamType, 0, flags);
RoboErik55011652014-07-09 15:05:53 -07001934 }
1935 return true;
1936 }
Jeff Brownb0418da2010-11-01 15:24:01 -07001937 case KeyEvent.KEYCODE_VOLUME_MUTE: {
Joe Onorato86f67862010-11-05 18:57:34 -07001938 // Similar code is in PhoneFallbackEventHandler in case the window
1939 // doesn't have one of these. In this case, we execute it here and
1940 // eat the event instead, because we have mVolumeControlStreamType
1941 // and they don't.
Mike Lockwoodce952c82011-11-14 10:47:42 -08001942 getAudioManager().handleKeyUp(event, mVolumeControlStreamType);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001943 return true;
1944 }
RoboErik55011652014-07-09 15:05:53 -07001945 // These are all the recognized media key codes in
1946 // KeyEvent.isMediaKey()
1947 case KeyEvent.KEYCODE_MEDIA_PLAY:
1948 case KeyEvent.KEYCODE_MEDIA_PAUSE:
1949 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
1950 case KeyEvent.KEYCODE_MUTE:
1951 case KeyEvent.KEYCODE_HEADSETHOOK:
1952 case KeyEvent.KEYCODE_MEDIA_STOP:
1953 case KeyEvent.KEYCODE_MEDIA_NEXT:
1954 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
1955 case KeyEvent.KEYCODE_MEDIA_REWIND:
1956 case KeyEvent.KEYCODE_MEDIA_RECORD:
1957 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
1958 if (mMediaController != null) {
1959 if (mMediaController.dispatchMediaButtonEvent(event)) {
1960 return true;
1961 }
1962 }
RoboErik28204a72014-07-17 12:17:27 -07001963 return false;
RoboErik55011652014-07-09 15:05:53 -07001964 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001965
1966 case KeyEvent.KEYCODE_MENU: {
Adam Powellf6148c52010-08-11 21:10:16 -07001967 onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId,
1968 event);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001969 return true;
1970 }
1971
Dianne Hackborna207baa2009-09-13 16:14:44 -07001972 case KeyEvent.KEYCODE_BACK: {
1973 if (featureId < 0) break;
Dianne Hackbornfed9cb52009-09-14 21:23:11 -07001974 if (event.isTracking() && !event.isCanceled()) {
1975 if (featureId == FEATURE_OPTIONS_PANEL) {
1976 PanelFeatureState st = getPanelState(featureId, false);
1977 if (st != null && st.isInExpandedMode) {
1978 // If the user is in an expanded menu and hits back, it
1979 // should go back to the icon menu
1980 reopenMenu(true);
1981 return true;
1982 }
Dianne Hackborna207baa2009-09-13 16:14:44 -07001983 }
Dianne Hackbornfed9cb52009-09-14 21:23:11 -07001984 closePanel(featureId);
1985 return true;
Dianne Hackborna207baa2009-09-13 16:14:44 -07001986 }
Dianne Hackbornfed9cb52009-09-14 21:23:11 -07001987 break;
Dianne Hackborna207baa2009-09-13 16:14:44 -07001988 }
1989
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001990 case KeyEvent.KEYCODE_SEARCH: {
1991 /*
1992 * Do this in onKeyUp since the Search key is also used for
1993 * chording quick launch shortcuts.
1994 */
Dianne Hackborna207baa2009-09-13 16:14:44 -07001995 if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001996 break;
1997 }
Dianne Hackborna207baa2009-09-13 16:14:44 -07001998 if (event.isTracking() && !event.isCanceled()) {
Tim Kilbourn6a975b32015-04-09 17:14:34 -07001999 launchDefaultSearch(event);
Dianne Hackborn0041e972009-07-24 17:14:43 -07002000 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002001 return true;
2002 }
2003 }
2004
2005 return false;
2006 }
2007
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002008 @Override
2009 protected void onActive() {
2010 }
2011
2012 @Override
2013 public final View getDecorView() {
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -07002014 if (mDecor == null || mForceDecorInstall) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002015 installDecor();
2016 }
2017 return mDecor;
2018 }
2019
2020 @Override
2021 public final View peekDecorView() {
2022 return mDecor;
2023 }
2024
2025 static private final String FOCUSED_ID_TAG = "android:focusedViewId";
Alan Viveretteec6cf182015-08-13 15:31:57 -04002026 static private final String ACCESSIBILITY_FOCUSED_ID_TAG = "android:accessibilityFocusedViewId";
2027 static private final String ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG =
2028 "android:accessibilityFocusedVirtualViewId";
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002029 static private final String VIEWS_TAG = "android:views";
2030 static private final String PANELS_TAG = "android:Panels";
Adam Powell6c6f5752010-08-20 18:34:46 -07002031 static private final String ACTION_BAR_TAG = "android:ActionBar";
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002032
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002033 /** {@inheritDoc} */
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002034 @Override
2035 public Bundle saveHierarchyState() {
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002036 Bundle outState = new Bundle();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002037 if (mContentParent == null) {
2038 return outState;
2039 }
2040
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002041 SparseArray<Parcelable> states = new SparseArray<Parcelable>();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002042 mContentParent.saveHierarchyState(states);
2043 outState.putSparseParcelableArray(VIEWS_TAG, states);
2044
Alan Viveretteec6cf182015-08-13 15:31:57 -04002045 // Save the focused view ID.
2046 final View focusedView = mContentParent.findFocus();
2047 if (focusedView != null && focusedView.getId() != View.NO_ID) {
2048 outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
2049 }
2050
2051 // Save the accessibility focused view ID.
Alan Viverette4cbd3ac2015-08-19 10:07:29 -04002052 if (mDecor != null) {
2053 final ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
2054 if (viewRootImpl != null) {
2055 final View accessFocusHost = viewRootImpl.getAccessibilityFocusedHost();
2056 if (accessFocusHost != null && accessFocusHost.getId() != View.NO_ID) {
2057 outState.putInt(ACCESSIBILITY_FOCUSED_ID_TAG, accessFocusHost.getId());
Alan Viveretteec6cf182015-08-13 15:31:57 -04002058
Alan Viverette4cbd3ac2015-08-19 10:07:29 -04002059 // If we have a focused virtual node ID, save that too.
2060 final AccessibilityNodeInfo accessFocusedNode =
2061 viewRootImpl.getAccessibilityFocusedVirtualView();
2062 if (accessFocusedNode != null) {
2063 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2064 accessFocusedNode.getSourceNodeId());
2065 outState.putInt(ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG, virtualNodeId);
2066 }
2067 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002068 }
2069 }
2070
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002071 // save the panels
2072 SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002073 savePanelState(panelStates);
2074 if (panelStates.size() > 0) {
2075 outState.putSparseParcelableArray(PANELS_TAG, panelStates);
2076 }
2077
Adam Powell4369e7d2014-05-17 14:16:08 -07002078 if (mDecorContentParent != null) {
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002079 SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>();
Adam Powell4369e7d2014-05-17 14:16:08 -07002080 mDecorContentParent.saveToolbarHierarchyState(actionBarStates);
Adam Powell8d02dea2011-05-31 21:35:13 -07002081 outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);
Adam Powell6c6f5752010-08-20 18:34:46 -07002082 }
2083
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002084 return outState;
2085 }
2086
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002087 /** {@inheritDoc} */
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002088 @Override
2089 public void restoreHierarchyState(Bundle savedInstanceState) {
2090 if (mContentParent == null) {
2091 return;
2092 }
2093
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002094 SparseArray<Parcelable> savedStates
2095 = savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002096 if (savedStates != null) {
2097 mContentParent.restoreHierarchyState(savedStates);
2098 }
2099
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002100 // restore the focused view
2101 int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002102 if (focusedViewId != View.NO_ID) {
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002103 View needsFocus = mContentParent.findViewById(focusedViewId);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002104 if (needsFocus != null) {
2105 needsFocus.requestFocus();
2106 } else {
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002107 Log.w(TAG,
2108 "Previously focused view reported id " + focusedViewId
2109 + " during save, but can't be found during restore.");
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002110 }
2111 }
2112
Alan Viveretteec6cf182015-08-13 15:31:57 -04002113 // Restore the accessibility focused view.
2114 final int accessFocusHostViewId = savedInstanceState.getInt(
2115 ACCESSIBILITY_FOCUSED_ID_TAG, View.NO_ID);
2116 final int accessFocusVirtualViewId = savedInstanceState.getInt(
2117 ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG, AccessibilityNodeInfo.UNDEFINED_ITEM_ID);
2118 tryRestoreAccessibilityFocus(accessFocusHostViewId, accessFocusVirtualViewId);
2119
2120 // Restore the panels.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002121 SparseArray<Parcelable> panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);
2122 if (panelStates != null) {
2123 restorePanelState(panelStates);
2124 }
Adam Powell6c6f5752010-08-20 18:34:46 -07002125
Adam Powell4369e7d2014-05-17 14:16:08 -07002126 if (mDecorContentParent != null) {
Adam Powell8d02dea2011-05-31 21:35:13 -07002127 SparseArray<Parcelable> actionBarStates =
2128 savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG);
Adam Powellfb5f1bc2012-05-17 19:30:35 -07002129 if (actionBarStates != null) {
Adam Powell31c91c82014-08-22 17:20:00 -07002130 doPendingInvalidatePanelMenu();
Adam Powell4369e7d2014-05-17 14:16:08 -07002131 mDecorContentParent.restoreToolbarHierarchyState(actionBarStates);
Adam Powellfb5f1bc2012-05-17 19:30:35 -07002132 } else {
2133 Log.w(TAG, "Missing saved instance states for action bar views! " +
2134 "State will not be restored.");
2135 }
Adam Powell6c6f5752010-08-20 18:34:46 -07002136 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002137 }
2138
Alan Viveretteec6cf182015-08-13 15:31:57 -04002139 private void tryRestoreAccessibilityFocus(int hostViewId, int virtualViewId) {
Alan Viverette4cbd3ac2015-08-19 10:07:29 -04002140 if (hostViewId != View.NO_ID && mDecor != null) {
2141 final View needsAccessFocus = mDecor.findViewById(hostViewId);
Alan Viveretteec6cf182015-08-13 15:31:57 -04002142 if (needsAccessFocus != null) {
2143 if (!tryFocusingVirtualView(needsAccessFocus, virtualViewId)
2144 && !needsAccessFocus.requestAccessibilityFocus()) {
2145 Log.w(TAG, "Failed to restore focus to previously accessibility"
2146 + " focused view with id " + hostViewId);
2147 }
2148 } else {
2149 Log.w(TAG, "Previously accessibility focused view reported id " + hostViewId
2150 + " during save, but can't be found during restore.");
2151 }
2152 }
2153 }
2154
2155 private boolean tryFocusingVirtualView(View host, int virtualViewId) {
2156 if (virtualViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
2157 final AccessibilityNodeProvider nodeProvider = host.getAccessibilityNodeProvider();
2158 if (nodeProvider != null) {
2159 return nodeProvider.performAction(virtualViewId,
2160 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
2161 }
2162 }
2163 return false;
2164 }
2165
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002166 /**
2167 * Invoked when the panels should freeze their state.
2168 *
2169 * @param icicles Save state into this. This is usually indexed by the
2170 * featureId. This will be given to {@link #restorePanelState} in the
2171 * future.
2172 */
2173 private void savePanelState(SparseArray<Parcelable> icicles) {
2174 PanelFeatureState[] panels = mPanels;
2175 if (panels == null) {
2176 return;
2177 }
2178
2179 for (int curFeatureId = panels.length - 1; curFeatureId >= 0; curFeatureId--) {
2180 if (panels[curFeatureId] != null) {
2181 icicles.put(curFeatureId, panels[curFeatureId].onSaveInstanceState());
2182 }
2183 }
2184 }
2185
2186 /**
2187 * Invoked when the panels should thaw their state from a previously frozen state.
2188 *
2189 * @param icicles The state saved by {@link #savePanelState} that needs to be thawed.
2190 */
2191 private void restorePanelState(SparseArray<Parcelable> icicles) {
2192 PanelFeatureState st;
Dmitry Tsyganyuk554bb012012-04-02 13:10:52 -05002193 int curFeatureId;
2194 for (int i = icicles.size() - 1; i >= 0; i--) {
2195 curFeatureId = icicles.keyAt(i);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002196 st = getPanelState(curFeatureId, false /* required */);
2197 if (st == null) {
2198 // The panel must not have been required, and is currently not around, skip it
2199 continue;
2200 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002201
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002202 st.onRestoreInstanceState(icicles.get(curFeatureId));
Adam Powell31bb97d2011-05-03 20:58:31 -07002203 invalidatePanelMenu(curFeatureId);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002204 }
2205
2206 /*
2207 * Implementation note: call openPanelsAfterRestore later to actually open the
2208 * restored panels.
2209 */
2210 }
2211
2212 /**
2213 * Opens the panels that have had their state restored. This should be
2214 * called sometime after {@link #restorePanelState} when it is safe to add
2215 * to the window manager.
2216 */
Wale Ogunwale8804af22015-11-17 09:18:15 -08002217 void openPanelsAfterRestore() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002218 PanelFeatureState[] panels = mPanels;
2219
2220 if (panels == null) {
2221 return;
2222 }
2223
2224 PanelFeatureState st;
2225 for (int i = panels.length - 1; i >= 0; i--) {
2226 st = panels[i];
Dianne Hackbornd0071442009-09-25 01:35:29 -07002227 // We restore the panel if it was last open; we skip it if it
2228 // now is open, to avoid a race condition if the user immediately
2229 // opens it when we are resuming.
Adam Powell11ed1d62011-07-11 21:19:59 -07002230 if (st != null) {
2231 st.applyFrozenState();
2232 if (!st.isOpen && st.wasLastOpen) {
2233 st.isInExpandedMode = st.wasLastExpanded;
2234 openPanel(st, null);
2235 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002236 }
2237 }
2238 }
2239
Adam Powell696cba52011-03-29 10:38:16 -07002240 private class PanelMenuPresenterCallback implements MenuPresenter.Callback {
2241 @Override
2242 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
2243 final Menu parentMenu = menu.getRootMenu();
2244 final boolean isSubMenu = parentMenu != menu;
2245 final PanelFeatureState panel = findMenuPanel(isSubMenu ? parentMenu : menu);
2246 if (panel != null) {
2247 if (isSubMenu) {
2248 callOnPanelClosed(panel.featureId, panel, parentMenu);
2249 closePanel(panel, true);
2250 } else {
2251 // Close the panel and only do the callback if the menu is being
2252 // closed completely, not if opening a sub menu
2253 closePanel(panel, allMenusAreClosing);
2254 }
2255 }
2256 }
2257
2258 @Override
2259 public boolean onOpenSubMenu(MenuBuilder subMenu) {
2260 if (subMenu == null && hasFeature(FEATURE_ACTION_BAR)) {
2261 Callback cb = getCallback();
2262 if (cb != null && !isDestroyed()) {
2263 cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
2264 }
2265 }
2266
2267 return true;
2268 }
2269 }
2270
2271 private final class ActionMenuPresenterCallback implements MenuPresenter.Callback {
2272 @Override
2273 public boolean onOpenSubMenu(MenuBuilder subMenu) {
2274 Callback cb = getCallback();
2275 if (cb != null) {
2276 cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
2277 return true;
2278 }
2279 return false;
2280 }
2281
2282 @Override
2283 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
2284 checkCloseActionMenu(menu);
2285 }
2286 }
2287
Stefan Kuhne61b47bb2015-07-28 14:04:25 -07002288 protected DecorView generateDecor(int featureId) {
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07002289 // System process doesn't have application context and in that case we need to directly use
2290 // the context we have. Otherwise we want the application context, so we don't cling to the
2291 // activity.
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07002292 Context context;
Filip Gruszczynski796b8c12015-12-22 14:46:21 -08002293 if (mUseDecorContext) {
2294 Context applicationContext = getContext().getApplicationContext();
2295 if (applicationContext == null) {
2296 context = getContext();
2297 } else {
2298 context = new DecorContext(applicationContext);
2299 if (mTheme != -1) {
2300 context.setTheme(mTheme);
2301 }
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07002302 }
Filip Gruszczynski796b8c12015-12-22 14:46:21 -08002303 } else {
2304 context = getContext();
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07002305 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002306 return new DecorView(context, featureId, this, getAttributes());
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002307 }
2308
2309 protected ViewGroup generateLayout(DecorView decor) {
2310 // Apply data from current theme.
2311
2312 TypedArray a = getWindowStyle();
2313
2314 if (false) {
2315 System.out.println("From style:");
2316 String s = "Attrs:";
Alan Viverette40982d42014-07-25 17:48:55 -07002317 for (int i = 0; i < R.styleable.Window.length; i++) {
2318 s = s + " " + Integer.toHexString(R.styleable.Window[i]) + "="
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002319 + a.getString(i);
2320 }
2321 System.out.println(s);
2322 }
2323
Alan Viverette40982d42014-07-25 17:48:55 -07002324 mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002325 int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
2326 & (~getForcedWindowFlags());
2327 if (mIsFloating) {
2328 setLayout(WRAP_CONTENT, WRAP_CONTENT);
2329 setFlags(0, flagsToUpdate);
2330 } else {
2331 setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
2332 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002333
Alan Viverette40982d42014-07-25 17:48:55 -07002334 if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002335 requestFeature(FEATURE_NO_TITLE);
Alan Viverette40982d42014-07-25 17:48:55 -07002336 } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
Adam Powell33b97432010-04-20 10:01:14 -07002337 // Don't allow an action bar if there is no title.
2338 requestFeature(FEATURE_ACTION_BAR);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002339 }
2340
Alan Viverette40982d42014-07-25 17:48:55 -07002341 if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {
Adam Powell6b336f82010-08-10 20:13:01 -07002342 requestFeature(FEATURE_ACTION_BAR_OVERLAY);
2343 }
2344
Alan Viverette40982d42014-07-25 17:48:55 -07002345 if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {
Adam Powell5d279772010-07-27 16:34:07 -07002346 requestFeature(FEATURE_ACTION_MODE_OVERLAY);
2347 }
2348
Alan Viverette40982d42014-07-25 17:48:55 -07002349 if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {
Will Haldean Brownca6234e2014-02-12 10:23:41 -08002350 requestFeature(FEATURE_SWIPE_TO_DISMISS);
2351 }
2352
Alan Viverette40982d42014-07-25 17:48:55 -07002353 if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
Dianne Hackbornc652de82013-02-15 16:32:56 -08002354 setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
2355 }
2356
Alan Viverette40982d42014-07-25 17:48:55 -07002357 if (a.getBoolean(R.styleable.Window_windowTranslucentStatus,
John Spurlockbd957402013-10-03 11:38:39 -04002358 false)) {
2359 setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS
2360 & (~getForcedWindowFlags()));
2361 }
2362
Alan Viverette40982d42014-07-25 17:48:55 -07002363 if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation,
John Spurlockbd957402013-10-03 11:38:39 -04002364 false)) {
2365 setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION
2366 & (~getForcedWindowFlags()));
2367 }
2368
Alan Viverette40982d42014-07-25 17:48:55 -07002369 if (a.getBoolean(R.styleable.Window_windowOverscan, false)) {
Dianne Hackbornc652de82013-02-15 16:32:56 -08002370 setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002371 }
2372
Alan Viverette40982d42014-07-25 17:48:55 -07002373 if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
Dianne Hackborn4bf7bcf2009-08-09 17:23:00 -07002374 setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
2375 }
2376
Alan Viverette40982d42014-07-25 17:48:55 -07002377 if (a.getBoolean(R.styleable.Window_windowEnableSplitTouch,
Jeff Brown46e75292010-11-10 16:53:45 -08002378 getContext().getApplicationInfo().targetSdkVersion
2379 >= android.os.Build.VERSION_CODES.HONEYCOMB)) {
2380 setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags()));
2381 }
2382
Alan Viverette40982d42014-07-25 17:48:55 -07002383 a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
2384 a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002385 if (DEBUG) Log.d(TAG, "Min width minor: " + mMinWidthMinor.coerceToString()
2386 + ", major: " + mMinWidthMajor.coerceToString());
Alan Viverette40982d42014-07-25 17:48:55 -07002387 if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {
Adam Powell40eec4c2012-02-15 17:10:58 -08002388 if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
Alan Viverette40982d42014-07-25 17:48:55 -07002389 a.getValue(R.styleable.Window_windowFixedWidthMajor,
Adam Powell40eec4c2012-02-15 17:10:58 -08002390 mFixedWidthMajor);
2391 }
Alan Viverette40982d42014-07-25 17:48:55 -07002392 if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) {
Adam Powell40eec4c2012-02-15 17:10:58 -08002393 if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue();
Alan Viverette40982d42014-07-25 17:48:55 -07002394 a.getValue(R.styleable.Window_windowFixedWidthMinor,
Adam Powell40eec4c2012-02-15 17:10:58 -08002395 mFixedWidthMinor);
2396 }
Alan Viverette40982d42014-07-25 17:48:55 -07002397 if (a.hasValue(R.styleable.Window_windowFixedHeightMajor)) {
Adam Powell40eec4c2012-02-15 17:10:58 -08002398 if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue();
Alan Viverette40982d42014-07-25 17:48:55 -07002399 a.getValue(R.styleable.Window_windowFixedHeightMajor,
Adam Powell40eec4c2012-02-15 17:10:58 -08002400 mFixedHeightMajor);
2401 }
Alan Viverette40982d42014-07-25 17:48:55 -07002402 if (a.hasValue(R.styleable.Window_windowFixedHeightMinor)) {
Adam Powell40eec4c2012-02-15 17:10:58 -08002403 if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
Alan Viverette40982d42014-07-25 17:48:55 -07002404 a.getValue(R.styleable.Window_windowFixedHeightMinor,
Adam Powell40eec4c2012-02-15 17:10:58 -08002405 mFixedHeightMinor);
2406 }
Alan Viverette40982d42014-07-25 17:48:55 -07002407 if (a.getBoolean(R.styleable.Window_windowContentTransitions, false)) {
Adam Powell18e905f2013-10-24 14:27:48 -07002408 requestFeature(FEATURE_CONTENT_TRANSITIONS);
Michael Kolb4bb047f2014-04-01 14:38:57 -07002409 }
George Mount9826f632014-09-11 08:50:09 -07002410 if (a.getBoolean(R.styleable.Window_windowActivityTransitions, false)) {
2411 requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
2412 }
Filip Gruszczynskib57503c2014-07-16 16:35:18 -07002413
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002414 mIsTranslucent = a.getBoolean(R.styleable.Window_windowIsTranslucent, false);
2415
Adam Powell82349c52011-08-23 13:53:56 -07002416 final Context context = getContext();
2417 final int targetSdk = context.getApplicationInfo().targetSdkVersion;
2418 final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
2419 final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
Dianne Hackborn955d8d62014-10-07 20:17:19 -07002420 final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP;
Adam Powell82349c52011-08-23 13:53:56 -07002421 final boolean targetHcNeedsOptions = context.getResources().getBoolean(
Alan Viverette40982d42014-07-25 17:48:55 -07002422 R.bool.target_honeycomb_needs_options_menu);
Adam Powell82349c52011-08-23 13:53:56 -07002423 final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
2424
2425 if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
Wale Ogunwale393b1c12014-10-18 16:22:01 -07002426 setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
Dianne Hackborn73ab6a42011-12-13 11:16:23 -08002427 } else {
Wale Ogunwale393b1c12014-10-18 16:22:01 -07002428 setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);
Daniel Sandlere02d8082010-10-08 15:13:22 -04002429 }
Adrian Roosea562512014-05-05 13:33:03 +02002430
Jorim Jaggi6e0ce282015-12-01 15:19:49 -08002431 if (!mForcedStatusBarColor) {
2432 mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
2433 }
2434 if (!mForcedNavigationBarColor) {
2435 mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
2436 }
2437
Adrian Roosea562512014-05-05 13:33:03 +02002438 // Non-floating windows on high end devices must put up decor beneath the system bars and
2439 // therefore must know about visibility changes of those.
2440 if (!mIsFloating && ActivityManager.isHighEndGfx()) {
2441 if (!targetPreL && a.getBoolean(
Alan Viverette40982d42014-07-25 17:48:55 -07002442 R.styleable.Window_windowDrawsSystemBarBackgrounds,
Adrian Roosea562512014-05-05 13:33:03 +02002443 false)) {
2444 setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
2445 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
2446 }
Adrian Roosea562512014-05-05 13:33:03 +02002447 }
Adrian Roosf4f84c92015-04-28 13:44:43 -07002448 if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) {
Adrian Roos75fa3852015-01-27 20:21:44 +01002449 decor.setSystemUiVisibility(
2450 decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
2451 }
Adrian Roosea562512014-05-05 13:33:03 +02002452
Dianne Hackborncfaf8872011-01-18 13:57:54 -08002453 if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
2454 >= android.os.Build.VERSION_CODES.HONEYCOMB) {
Dianne Hackbornef575752011-01-18 17:35:17 -08002455 if (a.getBoolean(
Alan Viverette40982d42014-07-25 17:48:55 -07002456 R.styleable.Window_windowCloseOnTouchOutside,
Dianne Hackbornef575752011-01-18 17:35:17 -08002457 false)) {
2458 setCloseOnTouchOutsideIfNotSet(true);
Dianne Hackborncfaf8872011-01-18 13:57:54 -08002459 }
2460 }
Alan Viveretteeb1d3792014-06-03 18:36:03 -07002461
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002462 WindowManager.LayoutParams params = getAttributes();
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002463
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002464 if (!hasSoftInputMode()) {
2465 params.softInputMode = a.getInt(
Alan Viverette40982d42014-07-25 17:48:55 -07002466 R.styleable.Window_windowSoftInputMode,
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002467 params.softInputMode);
2468 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002469
Alan Viverette40982d42014-07-25 17:48:55 -07002470 if (a.getBoolean(R.styleable.Window_backgroundDimEnabled,
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002471 mIsFloating)) {
2472 /* All dialogs should have the window dimmed */
2473 if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {
2474 params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
2475 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002476 if (!haveDimAmount()) {
2477 params.dimAmount = a.getFloat(
2478 android.R.styleable.Window_backgroundDimAmount, 0.5f);
2479 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002480 }
2481
2482 if (params.windowAnimations == 0) {
2483 params.windowAnimations = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07002484 R.styleable.Window_windowAnimationStyle, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002485 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002486
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002487 // The rest are only done if this window is not embedded; otherwise,
2488 // the values are inherited from our container.
2489 if (getContainer() == null) {
2490 if (mBackgroundDrawable == null) {
2491 if (mBackgroundResource == 0) {
2492 mBackgroundResource = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07002493 R.styleable.Window_windowBackground, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002494 }
2495 if (mFrameResource == 0) {
Alan Viverette40982d42014-07-25 17:48:55 -07002496 mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002497 }
Adam Powellf849a5e2014-09-11 15:09:36 -07002498 mBackgroundFallbackResource = a.getResourceId(
2499 R.styleable.Window_windowBackgroundFallback, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002500 if (false) {
2501 System.out.println("Background: "
2502 + Integer.toHexString(mBackgroundResource) + " Frame: "
2503 + Integer.toHexString(mFrameResource));
2504 }
2505 }
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002506 if (mLoadElevation) {
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -07002507 mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
2508 }
Alan Viverette40982d42014-07-25 17:48:55 -07002509 mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);
2510 mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002511 }
2512
2513 // Inflate the window decor.
2514
2515 int layoutResource;
2516 int features = getLocalFeatures();
2517 // System.out.println("Features: 0x" + Integer.toHexString(features));
Will Haldean Brownca6234e2014-02-12 10:23:41 -08002518 if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
Alan Viverette40982d42014-07-25 17:48:55 -07002519 layoutResource = R.layout.screen_swipe_dismiss;
Will Haldean Brownca6234e2014-02-12 10:23:41 -08002520 } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002521 if (mIsFloating) {
Adam Powell32aa2c92011-01-11 15:37:04 -08002522 TypedValue res = new TypedValue();
2523 getContext().getTheme().resolveAttribute(
Alan Viverette40982d42014-07-25 17:48:55 -07002524 R.attr.dialogTitleIconsDecorLayout, res, true);
Adam Powell32aa2c92011-01-11 15:37:04 -08002525 layoutResource = res.resourceId;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002526 } else {
Alan Viverette40982d42014-07-25 17:48:55 -07002527 layoutResource = R.layout.screen_title_icons;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002528 }
Adam Powellf4a6ec42010-08-24 14:18:10 -07002529 // XXX Remove this once action bar supports these features.
2530 removeFeature(FEATURE_ACTION_BAR);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002531 // System.out.println("Title Icons!");
Adam Powell6af97e12010-11-11 21:11:53 -08002532 } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
2533 && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002534 // Special case for a window with only a progress bar (and title).
2535 // XXX Need to have a no-title version of embedded windows.
Alan Viverette40982d42014-07-25 17:48:55 -07002536 layoutResource = R.layout.screen_progress;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002537 // System.out.println("Progress!");
2538 } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
2539 // Special case for a window with a custom title.
2540 // If the window is floating, we need a dialog layout
2541 if (mIsFloating) {
Adam Powell32aa2c92011-01-11 15:37:04 -08002542 TypedValue res = new TypedValue();
2543 getContext().getTheme().resolveAttribute(
Alan Viverette40982d42014-07-25 17:48:55 -07002544 R.attr.dialogCustomTitleDecorLayout, res, true);
Adam Powell32aa2c92011-01-11 15:37:04 -08002545 layoutResource = res.resourceId;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002546 } else {
Alan Viverette40982d42014-07-25 17:48:55 -07002547 layoutResource = R.layout.screen_custom_title;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002548 }
Adam Powellf4a6ec42010-08-24 14:18:10 -07002549 // XXX Remove this once action bar supports these features.
2550 removeFeature(FEATURE_ACTION_BAR);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002551 } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
2552 // If no other features and not embedded, only need a title.
2553 // If the window is floating, we need a dialog layout
2554 if (mIsFloating) {
Adam Powell32aa2c92011-01-11 15:37:04 -08002555 TypedValue res = new TypedValue();
2556 getContext().getTheme().resolveAttribute(
Alan Viverette40982d42014-07-25 17:48:55 -07002557 R.attr.dialogTitleDecorLayout, res, true);
Adam Powell32aa2c92011-01-11 15:37:04 -08002558 layoutResource = res.resourceId;
Adam Powell33b97432010-04-20 10:01:14 -07002559 } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
Adam Powelle021e6e2014-05-23 17:27:24 -07002560 layoutResource = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07002561 R.styleable.Window_windowActionBarFullscreenDecorLayout,
2562 R.layout.screen_action_bar);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002563 } else {
Alan Viverette40982d42014-07-25 17:48:55 -07002564 layoutResource = R.layout.screen_title;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002565 }
2566 // System.out.println("Title!");
Adam Powellf8419a02011-10-03 12:08:54 -07002567 } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
Alan Viverette40982d42014-07-25 17:48:55 -07002568 layoutResource = R.layout.screen_simple_overlay_action_mode;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002569 } else {
2570 // Embedded, so no decoration is needed.
Alan Viverette40982d42014-07-25 17:48:55 -07002571 layoutResource = R.layout.screen_simple;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002572 // System.out.println("Simple!");
2573 }
2574
2575 mDecor.startChanging();
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002576 mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002577
2578 ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
2579 if (contentParent == null) {
2580 throw new RuntimeException("Window couldn't find content container view");
2581 }
2582
2583 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
2584 ProgressBar progress = getCircularProgressBar(false);
2585 if (progress != null) {
2586 progress.setIndeterminate(true);
2587 }
2588 }
2589
Will Haldean Brownca6234e2014-02-12 10:23:41 -08002590 if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
2591 registerSwipeCallbacks();
2592 }
2593
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002594 // Remaining setup -- of background and title -- that only applies
2595 // to top-level windows.
2596 if (getContainer() == null) {
Alan Viverette49a22e82014-07-12 20:01:27 -07002597 final Drawable background;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002598 if (mBackgroundResource != 0) {
Alan Viverette49a22e82014-07-12 20:01:27 -07002599 background = getContext().getDrawable(mBackgroundResource);
2600 } else {
2601 background = mBackgroundDrawable;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002602 }
Alan Viverette49a22e82014-07-12 20:01:27 -07002603 mDecor.setWindowBackground(background);
2604
2605 final Drawable frame;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002606 if (mFrameResource != 0) {
Alan Viverette49a22e82014-07-12 20:01:27 -07002607 frame = getContext().getDrawable(mFrameResource);
2608 } else {
2609 frame = null;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002610 }
Alan Viverette49a22e82014-07-12 20:01:27 -07002611 mDecor.setWindowFrame(frame);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002612
Alan Viverette49a22e82014-07-12 20:01:27 -07002613 mDecor.setElevation(mElevation);
Alan Viverette2c183332014-08-07 13:43:05 -07002614 mDecor.setClipToOutline(mClipToOutline);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002615
2616 if (mTitle != null) {
2617 setTitle(mTitle);
2618 }
Alan Viverette49a22e82014-07-12 20:01:27 -07002619
2620 if (mTitleColor == 0) {
2621 mTitleColor = mTextColor;
2622 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002623 setTitleColor(mTitleColor);
2624 }
2625
2626 mDecor.finishChanging();
2627
2628 return contentParent;
2629 }
2630
Dianne Hackborncfaf8872011-01-18 13:57:54 -08002631 /** @hide */
2632 public void alwaysReadCloseOnTouchAttr() {
2633 mAlwaysReadCloseOnTouchAttr = true;
2634 }
2635
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002636 private void installDecor() {
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -07002637 mForceDecorInstall = false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002638 if (mDecor == null) {
Stefan Kuhne61b47bb2015-07-28 14:04:25 -07002639 mDecor = generateDecor(-1);
Adam Powell00f4d982010-03-24 11:17:03 -07002640 mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002641 mDecor.setIsRootNamespace(true);
Adam Powell4b6d93f2012-09-18 18:34:08 -07002642 if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
2643 mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
2644 }
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07002645 } else {
2646 mDecor.setWindow(this);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002647 }
2648 if (mContentParent == null) {
2649 mContentParent = generateLayout(mDecor);
2650
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002651 // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
2652 mDecor.makeOptionalFitsSystemWindows();
2653
Adam Powell4369e7d2014-05-17 14:16:08 -07002654 final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
Alan Viverette40982d42014-07-25 17:48:55 -07002655 R.id.decor_content_parent);
Adam Powell4369e7d2014-05-17 14:16:08 -07002656
2657 if (decorContentParent != null) {
2658 mDecorContentParent = decorContentParent;
2659 mDecorContentParent.setWindowCallback(getCallback());
2660 if (mDecorContentParent.getTitle() == null) {
2661 mDecorContentParent.setWindowTitle(mTitle);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002662 }
Adam Powell9b4bee02011-04-27 19:24:47 -07002663
Adam Powell4369e7d2014-05-17 14:16:08 -07002664 final int localFeatures = getLocalFeatures();
2665 for (int i = 0; i < FEATURE_MAX; i++) {
2666 if ((localFeatures & (1 << i)) != 0) {
2667 mDecorContentParent.initFeature(i);
Adam Powell9b0dc282013-07-31 13:58:43 -07002668 }
Adam Powell4369e7d2014-05-17 14:16:08 -07002669 }
Adam Powell9b0dc282013-07-31 13:58:43 -07002670
Adam Powell4369e7d2014-05-17 14:16:08 -07002671 mDecorContentParent.setUiOptions(mUiOptions);
Adam Powell640a66e2011-04-29 10:18:53 -07002672
Adam Powell4369e7d2014-05-17 14:16:08 -07002673 if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
2674 (mIconRes != 0 && !mDecorContentParent.hasIcon())) {
2675 mDecorContentParent.setIcon(mIconRes);
2676 } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
2677 mIconRes == 0 && !mDecorContentParent.hasIcon()) {
2678 mDecorContentParent.setIcon(
2679 getContext().getPackageManager().getDefaultActivityIcon());
2680 mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
2681 }
2682 if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
2683 (mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
2684 mDecorContentParent.setLogo(mLogoRes);
2685 }
Adam Powell9b4bee02011-04-27 19:24:47 -07002686
Adam Powell31c91c82014-08-22 17:20:00 -07002687 // Invalidate if the panel menu hasn't been created before this.
2688 // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
Adam Powell4369e7d2014-05-17 14:16:08 -07002689 // being called in the middle of onCreate or similar.
Adam Powell31c91c82014-08-22 17:20:00 -07002690 // A pending invalidation will typically be resolved before the posted message
2691 // would run normally in order to satisfy instance state restoration.
2692 PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
Jorim Jaggia16cc152015-06-01 16:55:05 -07002693 if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) {
Adam Powell31c91c82014-08-22 17:20:00 -07002694 invalidatePanelMenu(FEATURE_ACTION_BAR);
2695 }
Adam Powell4369e7d2014-05-17 14:16:08 -07002696 } else {
Alan Viverette891c9ee2016-01-08 13:43:15 -05002697 mTitleView = (TextView) findViewById(R.id.title);
Adam Powell4369e7d2014-05-17 14:16:08 -07002698 if (mTitleView != null) {
Adam Powell4369e7d2014-05-17 14:16:08 -07002699 if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
Alan Viverette891c9ee2016-01-08 13:43:15 -05002700 final View titleContainer = findViewById(R.id.title_container);
Adam Powell4369e7d2014-05-17 14:16:08 -07002701 if (titleContainer != null) {
2702 titleContainer.setVisibility(View.GONE);
2703 } else {
2704 mTitleView.setVisibility(View.GONE);
2705 }
Alan Viverette891c9ee2016-01-08 13:43:15 -05002706 mContentParent.setForeground(null);
Adam Powell4369e7d2014-05-17 14:16:08 -07002707 } else {
2708 mTitleView.setText(mTitle);
2709 }
Adam Powell33b97432010-04-20 10:01:14 -07002710 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002711 }
Adam Powell18e905f2013-10-24 14:27:48 -07002712
Adam Powellf849a5e2014-09-11 15:09:36 -07002713 if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
2714 mDecor.setBackgroundFallback(mBackgroundFallbackResource);
2715 }
2716
Adam Powell18e905f2013-10-24 14:27:48 -07002717 // Only inflate or create a new TransitionManager if the caller hasn't
2718 // already set a custom one.
George Mount9826f632014-09-11 08:50:09 -07002719 if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
George Mount31a21722014-03-24 17:44:36 -07002720 if (mTransitionManager == null) {
2721 final int transitionRes = getWindowStyle().getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07002722 R.styleable.Window_windowContentTransitionManager,
George Mount31a21722014-03-24 17:44:36 -07002723 0);
2724 if (transitionRes != 0) {
2725 final TransitionInflater inflater = TransitionInflater.from(getContext());
2726 mTransitionManager = inflater.inflateTransitionManager(transitionRes,
2727 mContentParent);
2728 } else {
2729 mTransitionManager = new TransitionManager();
2730 }
2731 }
2732
George Mount68f96d82014-07-31 13:13:10 -07002733 mEnterTransition = getTransition(mEnterTransition, null,
Alan Viverette40982d42014-07-25 17:48:55 -07002734 R.styleable.Window_windowEnterTransition);
George Mount68f96d82014-07-31 13:13:10 -07002735 mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,
2736 R.styleable.Window_windowReturnTransition);
2737 mExitTransition = getTransition(mExitTransition, null,
Alan Viverette40982d42014-07-25 17:48:55 -07002738 R.styleable.Window_windowExitTransition);
George Mount68f96d82014-07-31 13:13:10 -07002739 mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,
2740 R.styleable.Window_windowReenterTransition);
2741 mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null,
Alan Viverette40982d42014-07-25 17:48:55 -07002742 R.styleable.Window_windowSharedElementEnterTransition);
George Mount68f96d82014-07-31 13:13:10 -07002743 mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition,
2744 USE_DEFAULT_TRANSITION,
2745 R.styleable.Window_windowSharedElementReturnTransition);
2746 mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null,
Alan Viverette40982d42014-07-25 17:48:55 -07002747 R.styleable.Window_windowSharedElementExitTransition);
George Mount68f96d82014-07-31 13:13:10 -07002748 mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition,
2749 USE_DEFAULT_TRANSITION,
2750 R.styleable.Window_windowSharedElementReenterTransition);
George Mount31a21722014-03-24 17:44:36 -07002751 if (mAllowEnterTransitionOverlap == null) {
2752 mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(
George Mount68f96d82014-07-31 13:13:10 -07002753 R.styleable.Window_windowAllowEnterTransitionOverlap, true);
George Mount31a21722014-03-24 17:44:36 -07002754 }
George Mountc03da0e2014-08-22 17:04:02 -07002755 if (mAllowReturnTransitionOverlap == null) {
2756 mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(
2757 R.styleable.Window_windowAllowReturnTransitionOverlap, true);
Adam Powell18e905f2013-10-24 14:27:48 -07002758 }
George Mounted1e01d2014-06-05 13:49:12 -07002759 if (mBackgroundFadeDurationMillis < 0) {
2760 mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
George Mount68f96d82014-07-31 13:13:10 -07002761 R.styleable.Window_windowTransitionBackgroundFadeDuration,
George Mounted1e01d2014-06-05 13:49:12 -07002762 DEFAULT_BACKGROUND_FADE_DURATION_MS);
2763 }
George Mountb89d5cc2014-08-18 16:50:50 -07002764 if (mSharedElementsUseOverlay == null) {
2765 mSharedElementsUseOverlay = getWindowStyle().getBoolean(
2766 R.styleable.Window_windowSharedElementsUseOverlay, true);
2767 }
Adam Powell18e905f2013-10-24 14:27:48 -07002768 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002769 }
2770 }
2771
George Mount68f96d82014-07-31 13:13:10 -07002772 private Transition getTransition(Transition currentValue, Transition defaultValue, int id) {
2773 if (currentValue != defaultValue) {
George Mount31a21722014-03-24 17:44:36 -07002774 return currentValue;
2775 }
2776 int transitionId = getWindowStyle().getResourceId(id, -1);
George Mount68f96d82014-07-31 13:13:10 -07002777 Transition transition = defaultValue;
Alan Viverette40982d42014-07-25 17:48:55 -07002778 if (transitionId != -1 && transitionId != R.transition.no_transition) {
George Mount31a21722014-03-24 17:44:36 -07002779 TransitionInflater inflater = TransitionInflater.from(getContext());
2780 transition = inflater.inflateTransition(transitionId);
George Mount7f151642014-08-18 16:24:21 -07002781 if (transition instanceof TransitionSet &&
2782 ((TransitionSet)transition).getTransitionCount() == 0) {
2783 transition = null;
2784 }
George Mount31a21722014-03-24 17:44:36 -07002785 }
2786 return transition;
2787 }
2788
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002789 private Drawable loadImageURI(Uri uri) {
2790 try {
Alan Viverettead3c4a12014-06-02 17:12:58 -07002791 return Drawable.createFromStream(
2792 getContext().getContentResolver().openInputStream(uri), null);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002793 } catch (Exception e) {
2794 Log.w(TAG, "Unable to open content: " + uri);
2795 }
2796 return null;
2797 }
2798
2799 private DrawableFeatureState getDrawableState(int featureId, boolean required) {
2800 if ((getFeatures() & (1 << featureId)) == 0) {
2801 if (!required) {
2802 return null;
2803 }
2804 throw new RuntimeException("The feature has not been requested");
2805 }
2806
2807 DrawableFeatureState[] ar;
2808 if ((ar = mDrawables) == null || ar.length <= featureId) {
2809 DrawableFeatureState[] nar = new DrawableFeatureState[featureId + 1];
2810 if (ar != null) {
2811 System.arraycopy(ar, 0, nar, 0, ar.length);
2812 }
2813 mDrawables = ar = nar;
2814 }
2815
2816 DrawableFeatureState st = ar[featureId];
2817 if (st == null) {
2818 ar[featureId] = st = new DrawableFeatureState(featureId);
2819 }
2820 return st;
2821 }
2822
2823 /**
2824 * Gets a panel's state based on its feature ID.
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002825 *
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002826 * @param featureId The feature ID of the panel.
2827 * @param required Whether the panel is required (if it is required and it
2828 * isn't in our features, this throws an exception).
2829 * @return The panel state.
2830 */
Wale Ogunwale8804af22015-11-17 09:18:15 -08002831 PanelFeatureState getPanelState(int featureId, boolean required) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002832 return getPanelState(featureId, required, null);
2833 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002834
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002835 /**
2836 * Gets a panel's state based on its feature ID.
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002837 *
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002838 * @param featureId The feature ID of the panel.
2839 * @param required Whether the panel is required (if it is required and it
2840 * isn't in our features, this throws an exception).
2841 * @param convertPanelState Optional: If the panel state does not exist, use
2842 * this as the panel state.
2843 * @return The panel state.
2844 */
2845 private PanelFeatureState getPanelState(int featureId, boolean required,
2846 PanelFeatureState convertPanelState) {
2847 if ((getFeatures() & (1 << featureId)) == 0) {
2848 if (!required) {
2849 return null;
2850 }
2851 throw new RuntimeException("The feature has not been requested");
2852 }
2853
2854 PanelFeatureState[] ar;
2855 if ((ar = mPanels) == null || ar.length <= featureId) {
2856 PanelFeatureState[] nar = new PanelFeatureState[featureId + 1];
2857 if (ar != null) {
2858 System.arraycopy(ar, 0, nar, 0, ar.length);
2859 }
2860 mPanels = ar = nar;
2861 }
2862
2863 PanelFeatureState st = ar[featureId];
2864 if (st == null) {
2865 ar[featureId] = st = (convertPanelState != null)
2866 ? convertPanelState
2867 : new PanelFeatureState(featureId);
2868 }
2869 return st;
2870 }
2871
2872 @Override
2873 public final void setChildDrawable(int featureId, Drawable drawable) {
2874 DrawableFeatureState st = getDrawableState(featureId, true);
2875 st.child = drawable;
2876 updateDrawable(featureId, st, false);
2877 }
2878
2879 @Override
2880 public final void setChildInt(int featureId, int value) {
2881 updateInt(featureId, value, false);
2882 }
2883
2884 @Override
2885 public boolean isShortcutKey(int keyCode, KeyEvent event) {
Jose Lima7a22fc62015-01-23 17:24:22 -08002886 PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
2887 return st != null && st.menu != null && st.menu.isShortcutKey(keyCode, event);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002888 }
2889
2890 private void updateDrawable(int featureId, DrawableFeatureState st, boolean fromResume) {
2891 // Do nothing if the decor is not yet installed... an update will
2892 // need to be forced when we eventually become active.
2893 if (mContentParent == null) {
2894 return;
2895 }
2896
2897 final int featureMask = 1 << featureId;
2898
2899 if ((getFeatures() & featureMask) == 0 && !fromResume) {
2900 return;
2901 }
2902
2903 Drawable drawable = null;
2904 if (st != null) {
2905 drawable = st.child;
2906 if (drawable == null)
2907 drawable = st.local;
2908 if (drawable == null)
2909 drawable = st.def;
2910 }
2911 if ((getLocalFeatures() & featureMask) == 0) {
2912 if (getContainer() != null) {
2913 if (isActive() || fromResume) {
2914 getContainer().setChildDrawable(featureId, drawable);
2915 }
2916 }
2917 } else if (st != null && (st.cur != drawable || st.curAlpha != st.alpha)) {
2918 // System.out.println("Drawable changed: old=" + st.cur
2919 // + ", new=" + drawable);
2920 st.cur = drawable;
2921 st.curAlpha = st.alpha;
2922 onDrawableChanged(featureId, drawable, st.alpha);
2923 }
2924 }
2925
2926 private void updateInt(int featureId, int value, boolean fromResume) {
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002927
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002928 // Do nothing if the decor is not yet installed... an update will
2929 // need to be forced when we eventually become active.
2930 if (mContentParent == null) {
2931 return;
2932 }
2933
2934 final int featureMask = 1 << featureId;
2935
2936 if ((getFeatures() & featureMask) == 0 && !fromResume) {
2937 return;
2938 }
2939
2940 if ((getLocalFeatures() & featureMask) == 0) {
2941 if (getContainer() != null) {
2942 getContainer().setChildInt(featureId, value);
2943 }
2944 } else {
2945 onIntChanged(featureId, value);
2946 }
2947 }
2948
2949 private ImageView getLeftIconView() {
2950 if (mLeftIconView != null) {
2951 return mLeftIconView;
2952 }
2953 if (mContentParent == null) {
2954 installDecor();
2955 }
Alan Viverette40982d42014-07-25 17:48:55 -07002956 return (mLeftIconView = (ImageView)findViewById(R.id.left_icon));
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002957 }
2958
Adrian Roosea562512014-05-05 13:33:03 +02002959 @Override
2960 protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
2961 super.dispatchWindowAttributesChanged(attrs);
2962 if (mDecor != null) {
Adrian Roos05054bd2014-10-27 17:04:10 +01002963 mDecor.updateColorViews(null /* insets */, true /* animate */);
Adrian Roosea562512014-05-05 13:33:03 +02002964 }
2965 }
2966
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002967 private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) {
2968 if (mCircularProgressBar != null) {
2969 return mCircularProgressBar;
2970 }
2971 if (mContentParent == null && shouldInstallDecor) {
2972 installDecor();
2973 }
Alan Viverette40982d42014-07-25 17:48:55 -07002974 mCircularProgressBar = (ProgressBar) findViewById(R.id.progress_circular);
Adam Powell6af97e12010-11-11 21:11:53 -08002975 if (mCircularProgressBar != null) {
2976 mCircularProgressBar.setVisibility(View.INVISIBLE);
2977 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002978 return mCircularProgressBar;
2979 }
2980
2981 private ProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) {
2982 if (mHorizontalProgressBar != null) {
2983 return mHorizontalProgressBar;
2984 }
2985 if (mContentParent == null && shouldInstallDecor) {
2986 installDecor();
2987 }
Alan Viverette40982d42014-07-25 17:48:55 -07002988 mHorizontalProgressBar = (ProgressBar) findViewById(R.id.progress_horizontal);
Adam Powell6af97e12010-11-11 21:11:53 -08002989 if (mHorizontalProgressBar != null) {
2990 mHorizontalProgressBar.setVisibility(View.INVISIBLE);
2991 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002992 return mHorizontalProgressBar;
2993 }
2994
2995 private ImageView getRightIconView() {
2996 if (mRightIconView != null) {
2997 return mRightIconView;
2998 }
2999 if (mContentParent == null) {
3000 installDecor();
3001 }
Alan Viverette40982d42014-07-25 17:48:55 -07003002 return (mRightIconView = (ImageView)findViewById(R.id.right_icon));
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003003 }
3004
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003005 private void registerSwipeCallbacks() {
3006 SwipeDismissLayout swipeDismiss =
Alan Viverette40982d42014-07-25 17:48:55 -07003007 (SwipeDismissLayout) findViewById(R.id.content);
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003008 swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
3009 @Override
3010 public void onDismissed(SwipeDismissLayout layout) {
Stefan Kuhne1b420572015-08-07 10:50:19 -07003011 dispatchOnWindowDismissed(false /*finishTask*/);
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003012 }
3013 });
3014 swipeDismiss.setOnSwipeProgressChangedListener(
3015 new SwipeDismissLayout.OnSwipeProgressChangedListener() {
Mark Renoufd0761212014-04-30 20:50:30 -04003016 private static final float ALPHA_DECREASE = 0.5f;
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003017 private boolean mIsTranslucent = false;
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003018 @Override
3019 public void onSwipeProgressChanged(
3020 SwipeDismissLayout layout, float progress, float translate) {
3021 WindowManager.LayoutParams newParams = getAttributes();
3022 newParams.x = (int) translate;
Mark Renoufd0761212014-04-30 20:50:30 -04003023 newParams.alpha = 1 - (progress * ALPHA_DECREASE);
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003024 setAttributes(newParams);
3025
3026 int flags = 0;
3027 if (newParams.x == 0) {
3028 flags = FLAG_FULLSCREEN;
3029 } else {
3030 flags = FLAG_LAYOUT_NO_LIMITS;
3031 }
3032 setFlags(flags, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
3033 }
3034
3035 @Override
3036 public void onSwipeCancelled(SwipeDismissLayout layout) {
3037 WindowManager.LayoutParams newParams = getAttributes();
3038 newParams.x = 0;
Mindy Pereirab0ea4842014-04-17 14:01:04 -07003039 newParams.alpha = 1;
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003040 setAttributes(newParams);
3041 setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
3042 }
3043 });
3044 }
3045
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003046 /**
3047 * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)}
3048 * callback. This method will grab whatever extra state is needed for the
3049 * callback that isn't given in the parameters. If the panel is not open,
3050 * this will not perform the callback.
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003051 *
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003052 * @param featureId Feature ID of the panel that was closed. Must be given.
3053 * @param panel Panel that was closed. Optional but useful if there is no
3054 * menu given.
3055 * @param menu The menu that was closed. Optional, but give if you have.
3056 */
3057 private void callOnPanelClosed(int featureId, PanelFeatureState panel, Menu menu) {
3058 final Callback cb = getCallback();
3059 if (cb == null)
3060 return;
3061
3062 // Try to get a menu
3063 if (menu == null) {
3064 // Need a panel to grab the menu, so try to get that
3065 if (panel == null) {
3066 if ((featureId >= 0) && (featureId < mPanels.length)) {
3067 panel = mPanels[featureId];
3068 }
3069 }
3070
3071 if (panel != null) {
3072 // menu still may be null, which is okay--we tried our best
3073 menu = panel.menu;
3074 }
3075 }
3076
3077 // If the panel is not open, do not callback
3078 if ((panel != null) && (!panel.isOpen))
3079 return;
3080
Dianne Hackbornb66ad572011-03-01 17:10:30 -08003081 if (!isDestroyed()) {
3082 cb.onPanelClosed(featureId, menu);
3083 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003084 }
3085
3086 /**
3087 * Helper method for adding launch-search to most applications. Opens the
3088 * search window using default settings.
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003089 *
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003090 * @return true if search window opened
3091 */
Tim Kilbourn6a975b32015-04-09 17:14:34 -07003092 private boolean launchDefaultSearch(KeyEvent event) {
Dianne Hackbornfdf5b352014-10-08 17:43:48 -07003093 boolean result;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003094 final Callback cb = getCallback();
Dianne Hackbornb66ad572011-03-01 17:10:30 -08003095 if (cb == null || isDestroyed()) {
Dianne Hackbornfdf5b352014-10-08 17:43:48 -07003096 result = false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003097 } else {
Karl Rosaen323216b2009-07-20 14:00:29 -07003098 sendCloseSystemWindows("search");
Tim Kilbourn6a975b32015-04-09 17:14:34 -07003099 int deviceId = event.getDeviceId();
3100 SearchEvent searchEvent = null;
3101 if (deviceId != 0) {
3102 searchEvent = new SearchEvent(InputDevice.getDevice(deviceId));
3103 }
Adam Powell97900342015-04-15 13:12:52 -07003104 try {
3105 result = cb.onSearchRequested(searchEvent);
3106 } catch (AbstractMethodError e) {
3107 Log.e(TAG, "WindowCallback " + cb.getClass().getName() + " does not implement"
3108 + " method onSearchRequested(SearchEvent); fa", e);
3109 result = cb.onSearchRequested();
3110 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003111 }
Dianne Hackbornfdf5b352014-10-08 17:43:48 -07003112 if (!result && (getContext().getResources().getConfiguration().uiMode
3113 & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) {
3114 // On TVs, if the app doesn't implement search, we want to launch assist.
Tim Kilbourn0e5f1102015-06-05 16:18:09 -07003115 Bundle args = new Bundle();
3116 args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, event.getDeviceId());
Dianne Hackbornfdf5b352014-10-08 17:43:48 -07003117 return ((SearchManager)getContext().getSystemService(Context.SEARCH_SERVICE))
Jorim Jaggi165ce062015-07-06 16:18:11 -07003118 .launchLegacyAssist(null, UserHandle.myUserId(), args);
Dianne Hackbornfdf5b352014-10-08 17:43:48 -07003119 }
3120 return result;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003121 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003122
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003123 @Override
3124 public void setVolumeControlStream(int streamType) {
3125 mVolumeControlStreamType = streamType;
3126 }
3127
3128 @Override
3129 public int getVolumeControlStream() {
3130 return mVolumeControlStreamType;
3131 }
3132
RoboErik55011652014-07-09 15:05:53 -07003133 @Override
3134 public void setMediaController(MediaController controller) {
3135 mMediaController = controller;
3136 }
3137
3138 @Override
3139 public MediaController getMediaController() {
3140 return mMediaController;
3141 }
3142
George Mount31a21722014-03-24 17:44:36 -07003143 @Override
3144 public void setEnterTransition(Transition enterTransition) {
3145 mEnterTransition = enterTransition;
3146 }
3147
3148 @Override
George Mount68f96d82014-07-31 13:13:10 -07003149 public void setReturnTransition(Transition transition) {
3150 mReturnTransition = transition;
3151 }
3152
3153 @Override
George Mount31a21722014-03-24 17:44:36 -07003154 public void setExitTransition(Transition exitTransition) {
3155 mExitTransition = exitTransition;
3156 }
3157
3158 @Override
George Mount68f96d82014-07-31 13:13:10 -07003159 public void setReenterTransition(Transition transition) {
3160 mReenterTransition = transition;
3161 }
3162
3163 @Override
George Mount31a21722014-03-24 17:44:36 -07003164 public void setSharedElementEnterTransition(Transition sharedElementEnterTransition) {
3165 mSharedElementEnterTransition = sharedElementEnterTransition;
3166 }
3167
3168 @Override
George Mount68f96d82014-07-31 13:13:10 -07003169 public void setSharedElementReturnTransition(Transition transition) {
3170 mSharedElementReturnTransition = transition;
3171 }
3172
3173 @Override
George Mount31a21722014-03-24 17:44:36 -07003174 public void setSharedElementExitTransition(Transition sharedElementExitTransition) {
3175 mSharedElementExitTransition = sharedElementExitTransition;
3176 }
3177
3178 @Override
George Mount68f96d82014-07-31 13:13:10 -07003179 public void setSharedElementReenterTransition(Transition transition) {
3180 mSharedElementReenterTransition = transition;
3181 }
3182
3183 @Override
George Mount31a21722014-03-24 17:44:36 -07003184 public Transition getEnterTransition() {
3185 return mEnterTransition;
3186 }
3187
3188 @Override
George Mount68f96d82014-07-31 13:13:10 -07003189 public Transition getReturnTransition() {
3190 return mReturnTransition == USE_DEFAULT_TRANSITION ? getEnterTransition()
3191 : mReturnTransition;
3192 }
3193
3194 @Override
George Mount31a21722014-03-24 17:44:36 -07003195 public Transition getExitTransition() {
3196 return mExitTransition;
3197 }
3198
3199 @Override
George Mount68f96d82014-07-31 13:13:10 -07003200 public Transition getReenterTransition() {
3201 return mReenterTransition == USE_DEFAULT_TRANSITION ? getExitTransition()
3202 : mReenterTransition;
3203 }
3204
3205 @Override
George Mount31a21722014-03-24 17:44:36 -07003206 public Transition getSharedElementEnterTransition() {
3207 return mSharedElementEnterTransition;
3208 }
3209
3210 @Override
George Mount68f96d82014-07-31 13:13:10 -07003211 public Transition getSharedElementReturnTransition() {
3212 return mSharedElementReturnTransition == USE_DEFAULT_TRANSITION
3213 ? getSharedElementEnterTransition() : mSharedElementReturnTransition;
3214 }
3215
3216 @Override
George Mount31a21722014-03-24 17:44:36 -07003217 public Transition getSharedElementExitTransition() {
3218 return mSharedElementExitTransition;
3219 }
3220
3221 @Override
George Mount68f96d82014-07-31 13:13:10 -07003222 public Transition getSharedElementReenterTransition() {
3223 return mSharedElementReenterTransition == USE_DEFAULT_TRANSITION
3224 ? getSharedElementExitTransition() : mSharedElementReenterTransition;
3225 }
3226
3227 @Override
George Mount31a21722014-03-24 17:44:36 -07003228 public void setAllowEnterTransitionOverlap(boolean allow) {
3229 mAllowEnterTransitionOverlap = allow;
3230 }
3231
3232 @Override
3233 public boolean getAllowEnterTransitionOverlap() {
3234 return (mAllowEnterTransitionOverlap == null) ? true : mAllowEnterTransitionOverlap;
3235 }
3236
3237 @Override
George Mountc03da0e2014-08-22 17:04:02 -07003238 public void setAllowReturnTransitionOverlap(boolean allowExitTransitionOverlap) {
3239 mAllowReturnTransitionOverlap = allowExitTransitionOverlap;
George Mount31a21722014-03-24 17:44:36 -07003240 }
3241
3242 @Override
George Mountc03da0e2014-08-22 17:04:02 -07003243 public boolean getAllowReturnTransitionOverlap() {
3244 return (mAllowReturnTransitionOverlap == null) ? true : mAllowReturnTransitionOverlap;
George Mount31a21722014-03-24 17:44:36 -07003245 }
3246
George Mounted1e01d2014-06-05 13:49:12 -07003247 @Override
3248 public long getTransitionBackgroundFadeDuration() {
3249 return (mBackgroundFadeDurationMillis < 0) ? DEFAULT_BACKGROUND_FADE_DURATION_MS
3250 : mBackgroundFadeDurationMillis;
3251 }
3252
3253 @Override
3254 public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) {
3255 if (fadeDurationMillis < 0) {
3256 throw new IllegalArgumentException("negative durations are not allowed");
3257 }
3258 mBackgroundFadeDurationMillis = fadeDurationMillis;
3259 }
3260
George Mountb89d5cc2014-08-18 16:50:50 -07003261 @Override
3262 public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) {
3263 mSharedElementsUseOverlay = sharedElementsUseOverlay;
3264 }
3265
3266 @Override
3267 public boolean getSharedElementsUseOverlay() {
3268 return (mSharedElementsUseOverlay == null) ? true : mSharedElementsUseOverlay;
3269 }
3270
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003271 private static final class DrawableFeatureState {
3272 DrawableFeatureState(int _featureId) {
3273 featureId = _featureId;
3274 }
3275
3276 final int featureId;
3277
3278 int resid;
3279
3280 Uri uri;
3281
3282 Drawable local;
3283
3284 Drawable child;
3285
3286 Drawable def;
3287
3288 Drawable cur;
3289
3290 int alpha = 255;
3291
3292 int curAlpha = 255;
3293 }
3294
Wale Ogunwale8804af22015-11-17 09:18:15 -08003295 static final class PanelFeatureState {
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003296
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003297 /** Feature ID for this panel. */
3298 int featureId;
3299
3300 // Information pulled from the style for this panel.
3301
3302 int background;
3303
3304 /** The background when the panel spans the entire available width. */
3305 int fullBackground;
3306
3307 int gravity;
3308
3309 int x;
3310
3311 int y;
3312
3313 int windowAnimations;
3314
3315 /** Dynamic state of the panel. */
3316 DecorView decorView;
3317
3318 /** The panel that was returned by onCreatePanelView(). */
3319 View createdPanelView;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003320
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003321 /** The panel that we are actually showing. */
3322 View shownPanelView;
3323
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003324 /** Use {@link #setMenu} to set this. */
Adam Powell696cba52011-03-29 10:38:16 -07003325 MenuBuilder menu;
3326
3327 IconMenuPresenter iconMenuPresenter;
Adam Powelldfee59a2011-08-05 20:48:30 -07003328 ListMenuPresenter listMenuPresenter;
3329
3330 /** true if this menu will show in single-list compact mode */
3331 boolean isCompact;
3332
3333 /** Theme resource ID for list elements of the panel menu */
3334 int listPresenterTheme;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003335
3336 /**
3337 * Whether the panel has been prepared (see
3338 * {@link PhoneWindow#preparePanel}).
3339 */
3340 boolean isPrepared;
3341
3342 /**
3343 * Whether an item's action has been performed. This happens in obvious
3344 * scenarios (user clicks on menu item), but can also happen with
3345 * chording menu+(shortcut key).
3346 */
3347 boolean isHandled;
3348
3349 boolean isOpen;
3350
3351 /**
3352 * True if the menu is in expanded mode, false if the menu is in icon
3353 * mode
3354 */
3355 boolean isInExpandedMode;
3356
3357 public boolean qwertyMode;
3358
3359 boolean refreshDecorView;
3360
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07003361 boolean refreshMenuContent;
Alan Viveretteeb1d3792014-06-03 18:36:03 -07003362
Dianne Hackbornd0071442009-09-25 01:35:29 -07003363 boolean wasLastOpen;
Alan Viveretteeb1d3792014-06-03 18:36:03 -07003364
Dianne Hackbornd0071442009-09-25 01:35:29 -07003365 boolean wasLastExpanded;
Alan Viveretteeb1d3792014-06-03 18:36:03 -07003366
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003367 /**
3368 * Contains the state of the menu when told to freeze.
3369 */
3370 Bundle frozenMenuState;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003371
Adam Powell038f1c82011-07-21 14:28:10 -07003372 /**
3373 * Contains the state of associated action views when told to freeze.
3374 * These are saved across invalidations.
3375 */
3376 Bundle frozenActionViewState;
3377
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003378 PanelFeatureState(int featureId) {
3379 this.featureId = featureId;
3380
3381 refreshDecorView = false;
3382 }
3383
Adam Powelldfee59a2011-08-05 20:48:30 -07003384 public boolean isInListMode() {
3385 return isInExpandedMode || isCompact;
3386 }
3387
Adam Powell526b9312011-04-22 15:42:05 -07003388 public boolean hasPanelItems() {
3389 if (shownPanelView == null) return false;
Adam Powell4fd8d5332011-08-17 14:54:41 -07003390 if (createdPanelView != null) return true;
Adam Powell526b9312011-04-22 15:42:05 -07003391
Adam Powelldfee59a2011-08-05 20:48:30 -07003392 if (isCompact || isInExpandedMode) {
3393 return listMenuPresenter.getAdapter().getCount() > 0;
Adam Powell526b9312011-04-22 15:42:05 -07003394 } else {
3395 return ((ViewGroup) shownPanelView).getChildCount() > 0;
3396 }
3397 }
3398
Adam Powell696cba52011-03-29 10:38:16 -07003399 /**
3400 * Unregister and free attached MenuPresenters. They will be recreated as needed.
3401 */
3402 public void clearMenuPresenters() {
3403 if (menu != null) {
3404 menu.removeMenuPresenter(iconMenuPresenter);
Adam Powelldfee59a2011-08-05 20:48:30 -07003405 menu.removeMenuPresenter(listMenuPresenter);
Adam Powell696cba52011-03-29 10:38:16 -07003406 }
3407 iconMenuPresenter = null;
Adam Powelldfee59a2011-08-05 20:48:30 -07003408 listMenuPresenter = null;
Adam Powell696cba52011-03-29 10:38:16 -07003409 }
3410
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003411 void setStyle(Context context) {
Alan Viverette40982d42014-07-25 17:48:55 -07003412 TypedArray a = context.obtainStyledAttributes(R.styleable.Theme);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003413 background = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07003414 R.styleable.Theme_panelBackground, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003415 fullBackground = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07003416 R.styleable.Theme_panelFullBackground, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003417 windowAnimations = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07003418 R.styleable.Theme_windowAnimationStyle, 0);
Adam Powelldfee59a2011-08-05 20:48:30 -07003419 isCompact = a.getBoolean(
Alan Viverette40982d42014-07-25 17:48:55 -07003420 R.styleable.Theme_panelMenuIsCompact, false);
Adam Powelldfee59a2011-08-05 20:48:30 -07003421 listPresenterTheme = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07003422 R.styleable.Theme_panelMenuListTheme,
3423 R.style.Theme_ExpandedMenu);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003424 a.recycle();
3425 }
3426
Adam Powell696cba52011-03-29 10:38:16 -07003427 void setMenu(MenuBuilder menu) {
Adam Powell1d07e162011-09-07 20:46:24 -07003428 if (menu == this.menu) return;
3429
3430 if (this.menu != null) {
3431 this.menu.removeMenuPresenter(iconMenuPresenter);
3432 this.menu.removeMenuPresenter(listMenuPresenter);
3433 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003434 this.menu = menu;
Adam Powell1d07e162011-09-07 20:46:24 -07003435 if (menu != null) {
3436 if (iconMenuPresenter != null) menu.addMenuPresenter(iconMenuPresenter);
3437 if (listMenuPresenter != null) menu.addMenuPresenter(listMenuPresenter);
3438 }
Adam Powell696cba52011-03-29 10:38:16 -07003439 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003440
Adam Powell538e5652011-10-11 13:47:08 -07003441 MenuView getListMenuView(Context context, MenuPresenter.Callback cb) {
Adam Powell696cba52011-03-29 10:38:16 -07003442 if (menu == null) return null;
3443
Adam Powelldfee59a2011-08-05 20:48:30 -07003444 if (!isCompact) {
Adam Powell538e5652011-10-11 13:47:08 -07003445 getIconMenuView(context, cb); // Need this initialized to know where our offset goes
Adam Powell696cba52011-03-29 10:38:16 -07003446 }
3447
Adam Powelldfee59a2011-08-05 20:48:30 -07003448 if (listMenuPresenter == null) {
3449 listMenuPresenter = new ListMenuPresenter(
Alan Viverette40982d42014-07-25 17:48:55 -07003450 R.layout.list_menu_item_layout, listPresenterTheme);
Adam Powelldfee59a2011-08-05 20:48:30 -07003451 listMenuPresenter.setCallback(cb);
Alan Viverette40982d42014-07-25 17:48:55 -07003452 listMenuPresenter.setId(R.id.list_menu_presenter);
Adam Powelldfee59a2011-08-05 20:48:30 -07003453 menu.addMenuPresenter(listMenuPresenter);
3454 }
3455
3456 if (iconMenuPresenter != null) {
3457 listMenuPresenter.setItemIndexOffset(
3458 iconMenuPresenter.getNumActualItemsShown());
3459 }
3460 MenuView result = listMenuPresenter.getMenuView(decorView);
Adam Powell696cba52011-03-29 10:38:16 -07003461
Adam Powell696cba52011-03-29 10:38:16 -07003462 return result;
3463 }
3464
Adam Powell538e5652011-10-11 13:47:08 -07003465 MenuView getIconMenuView(Context context, MenuPresenter.Callback cb) {
Adam Powell696cba52011-03-29 10:38:16 -07003466 if (menu == null) return null;
3467
Adam Powell696cba52011-03-29 10:38:16 -07003468 if (iconMenuPresenter == null) {
Adam Powell538e5652011-10-11 13:47:08 -07003469 iconMenuPresenter = new IconMenuPresenter(context);
Adam Powell696cba52011-03-29 10:38:16 -07003470 iconMenuPresenter.setCallback(cb);
Alan Viverette40982d42014-07-25 17:48:55 -07003471 iconMenuPresenter.setId(R.id.icon_menu_presenter);
Adam Powell696cba52011-03-29 10:38:16 -07003472 menu.addMenuPresenter(iconMenuPresenter);
Adam Powell696cba52011-03-29 10:38:16 -07003473 }
3474
3475 MenuView result = iconMenuPresenter.getMenuView(decorView);
3476
Adam Powell696cba52011-03-29 10:38:16 -07003477 return result;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003478 }
3479
3480 Parcelable onSaveInstanceState() {
3481 SavedState savedState = new SavedState();
3482 savedState.featureId = featureId;
3483 savedState.isOpen = isOpen;
3484 savedState.isInExpandedMode = isInExpandedMode;
3485
3486 if (menu != null) {
3487 savedState.menuState = new Bundle();
Adam Powell11ed1d62011-07-11 21:19:59 -07003488 menu.savePresenterStates(savedState.menuState);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003489 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003490
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003491 return savedState;
3492 }
3493
3494 void onRestoreInstanceState(Parcelable state) {
3495 SavedState savedState = (SavedState) state;
3496 featureId = savedState.featureId;
Dianne Hackbornd0071442009-09-25 01:35:29 -07003497 wasLastOpen = savedState.isOpen;
3498 wasLastExpanded = savedState.isInExpandedMode;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003499 frozenMenuState = savedState.menuState;
3500
3501 /*
3502 * A LocalActivityManager keeps the same instance of this class around.
3503 * The first time the menu is being shown after restoring, the
3504 * Activity.onCreateOptionsMenu should be called. But, if it is the
3505 * same instance then menu != null and we won't call that method.
Adam Powell31bb97d2011-05-03 20:58:31 -07003506 * We clear any cached views here. The caller should invalidatePanelMenu.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003507 */
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003508 createdPanelView = null;
3509 shownPanelView = null;
3510 decorView = null;
3511 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003512
Adam Powell11ed1d62011-07-11 21:19:59 -07003513 void applyFrozenState() {
3514 if (menu != null && frozenMenuState != null) {
3515 menu.restorePresenterStates(frozenMenuState);
3516 frozenMenuState = null;
3517 }
3518 }
3519
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003520 private static class SavedState implements Parcelable {
3521 int featureId;
3522 boolean isOpen;
3523 boolean isInExpandedMode;
3524 Bundle menuState;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003525
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003526 public int describeContents() {
3527 return 0;
3528 }
3529
3530 public void writeToParcel(Parcel dest, int flags) {
3531 dest.writeInt(featureId);
3532 dest.writeInt(isOpen ? 1 : 0);
3533 dest.writeInt(isInExpandedMode ? 1 : 0);
3534
3535 if (isOpen) {
3536 dest.writeBundle(menuState);
3537 }
3538 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003539
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003540 private static SavedState readFromParcel(Parcel source) {
3541 SavedState savedState = new SavedState();
3542 savedState.featureId = source.readInt();
3543 savedState.isOpen = source.readInt() == 1;
3544 savedState.isInExpandedMode = source.readInt() == 1;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003545
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003546 if (savedState.isOpen) {
3547 savedState.menuState = source.readBundle();
3548 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003549
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003550 return savedState;
3551 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003552
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003553 public static final Parcelable.Creator<SavedState> CREATOR
3554 = new Parcelable.Creator<SavedState>() {
3555 public SavedState createFromParcel(Parcel in) {
3556 return readFromParcel(in);
3557 }
3558
3559 public SavedState[] newArray(int size) {
3560 return new SavedState[size];
3561 }
3562 };
3563 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003564
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003565 }
3566
Adam Powell6711f3b2015-05-06 15:57:09 -07003567 static class RotationWatcher extends Stub {
Adam Powelldfee59a2011-08-05 20:48:30 -07003568 private Handler mHandler;
3569 private final Runnable mRotationChanged = new Runnable() {
3570 public void run() {
3571 dispatchRotationChanged();
3572 }
3573 };
3574 private final ArrayList<WeakReference<PhoneWindow>> mWindows =
3575 new ArrayList<WeakReference<PhoneWindow>>();
3576 private boolean mIsWatching;
3577
3578 @Override
3579 public void onRotationChanged(int rotation) throws RemoteException {
3580 mHandler.post(mRotationChanged);
3581 }
3582
3583 public void addWindow(PhoneWindow phoneWindow) {
3584 synchronized (mWindows) {
3585 if (!mIsWatching) {
3586 try {
3587 WindowManagerHolder.sWindowManager.watchRotation(this);
3588 mHandler = new Handler();
3589 mIsWatching = true;
3590 } catch (RemoteException ex) {
3591 Log.e(TAG, "Couldn't start watching for device rotation", ex);
3592 }
3593 }
3594 mWindows.add(new WeakReference<PhoneWindow>(phoneWindow));
3595 }
3596 }
3597
3598 public void removeWindow(PhoneWindow phoneWindow) {
3599 synchronized (mWindows) {
3600 int i = 0;
3601 while (i < mWindows.size()) {
3602 final WeakReference<PhoneWindow> ref = mWindows.get(i);
3603 final PhoneWindow win = ref.get();
3604 if (win == null || win == phoneWindow) {
3605 mWindows.remove(i);
3606 } else {
3607 i++;
3608 }
3609 }
3610 }
3611 }
3612
3613 void dispatchRotationChanged() {
3614 synchronized (mWindows) {
3615 int i = 0;
3616 while (i < mWindows.size()) {
3617 final WeakReference<PhoneWindow> ref = mWindows.get(i);
3618 final PhoneWindow win = ref.get();
3619 if (win != null) {
3620 win.onOptionsPanelRotationChanged();
3621 i++;
3622 } else {
3623 mWindows.remove(i);
3624 }
3625 }
3626 }
3627 }
3628 }
3629
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003630 /**
3631 * Simple implementation of MenuBuilder.Callback that:
3632 * <li> Opens a submenu when selected.
3633 * <li> Calls back to the callback's onMenuItemSelected when an item is
3634 * selected.
3635 */
Alan Viverette77fb85e2015-12-14 11:42:44 -05003636 public static final class PhoneWindowMenuCallback
3637 implements MenuBuilder.Callback, MenuPresenter.Callback {
3638 private static final int FEATURE_ID = FEATURE_CONTEXT_MENU;
3639
3640 private final PhoneWindow mWindow;
3641
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003642 private MenuDialogHelper mSubMenuHelper;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003643
Alan Viverette77fb85e2015-12-14 11:42:44 -05003644 private boolean mShowDialogForSubmenu;
3645
3646 public PhoneWindowMenuCallback(PhoneWindow window) {
3647 mWindow = window;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003648 }
3649
Alan Viverette77fb85e2015-12-14 11:42:44 -05003650 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003651 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
Adam Powelld1f42072011-05-03 17:20:14 -07003652 if (menu.getRootMenu() != menu) {
3653 onCloseSubMenu(menu);
3654 }
3655
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003656 if (allMenusAreClosing) {
Alan Viverette77fb85e2015-12-14 11:42:44 -05003657 final Callback callback = mWindow.getCallback();
3658 if (callback != null && !mWindow.isDestroyed()) {
3659 callback.onPanelClosed(FEATURE_ID, menu);
Dianne Hackbornb66ad572011-03-01 17:10:30 -08003660 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003661
Alan Viverette77fb85e2015-12-14 11:42:44 -05003662 if (menu == mWindow.mContextMenu) {
3663 mWindow.dismissContextMenu();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003664 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003665
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003666 // Dismiss the submenu, if it is showing
3667 if (mSubMenuHelper != null) {
3668 mSubMenuHelper.dismiss();
3669 mSubMenuHelper = null;
3670 }
3671 }
3672 }
3673
Alan Viverette77fb85e2015-12-14 11:42:44 -05003674 private void onCloseSubMenu(MenuBuilder menu) {
3675 final Callback callback = mWindow.getCallback();
3676 if (callback != null && !mWindow.isDestroyed()) {
3677 callback.onPanelClosed(FEATURE_ID, menu.getRootMenu());
Dianne Hackbornb66ad572011-03-01 17:10:30 -08003678 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003679 }
3680
Alan Viverette77fb85e2015-12-14 11:42:44 -05003681 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003682 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
Alan Viverette77fb85e2015-12-14 11:42:44 -05003683 final Callback callback = mWindow.getCallback();
3684 return callback != null && !mWindow.isDestroyed()
3685 && callback.onMenuItemSelected(FEATURE_ID, item);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003686 }
3687
Alan Viverette77fb85e2015-12-14 11:42:44 -05003688 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003689 public void onMenuModeChange(MenuBuilder menu) {
3690 }
3691
Alan Viverette77fb85e2015-12-14 11:42:44 -05003692 @Override
Adam Powelld1f42072011-05-03 17:20:14 -07003693 public boolean onOpenSubMenu(MenuBuilder subMenu) {
Alan Viverette77fb85e2015-12-14 11:42:44 -05003694 if (subMenu == null) {
3695 return false;
3696 }
Adam Powell823f0742011-09-21 17:17:01 -07003697
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003698 // Set a simple callback for the submenu
3699 subMenu.setCallback(this);
3700
Alan Viverette77fb85e2015-12-14 11:42:44 -05003701 if (mShowDialogForSubmenu) {
3702 // The window manager will give us a valid window token
3703 mSubMenuHelper = new MenuDialogHelper(subMenu);
3704 mSubMenuHelper.show(null);
3705 return true;
3706 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003707
Alan Viverette77fb85e2015-12-14 11:42:44 -05003708 return false;
3709 }
3710
3711 public void setShowDialogForSubmenu(boolean enabled) {
3712 mShowDialogForSubmenu = enabled;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003713 }
3714 }
3715
Wale Ogunwale8804af22015-11-17 09:18:15 -08003716 int getLocalFeaturesPrivate() {
3717 return super.getLocalFeatures();
3718 }
Adrian Roos05054bd2014-10-27 17:04:10 +01003719
Wale Ogunwale8804af22015-11-17 09:18:15 -08003720 protected void setDefaultWindowFormat(int format) {
3721 super.setDefaultWindowFormat(format);
Adrian Roos05054bd2014-10-27 17:04:10 +01003722 }
3723
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003724 void sendCloseSystemWindows() {
Jorim Jaggib10e33f2015-02-04 21:57:40 +01003725 sendCloseSystemWindows(getContext(), null);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003726 }
3727
3728 void sendCloseSystemWindows(String reason) {
Jorim Jaggib10e33f2015-02-04 21:57:40 +01003729 sendCloseSystemWindows(getContext(), reason);
3730 }
3731
3732 public static void sendCloseSystemWindows(Context context, String reason) {
3733 if (ActivityManagerNative.isSystemReady()) {
3734 try {
3735 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
3736 } catch (RemoteException e) {
3737 }
3738 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003739 }
Adrian Roos217ccd22014-05-09 14:29:04 +02003740
3741 @Override
3742 public int getStatusBarColor() {
Adrian Roos34e65442014-05-17 02:35:33 +02003743 return mStatusBarColor;
Adrian Roos217ccd22014-05-09 14:29:04 +02003744 }
3745
3746 @Override
3747 public void setStatusBarColor(int color) {
Adrian Roos34e65442014-05-17 02:35:33 +02003748 mStatusBarColor = color;
3749 mForcedStatusBarColor = true;
3750 if (mDecor != null) {
Adrian Roos05054bd2014-10-27 17:04:10 +01003751 mDecor.updateColorViews(null, false /* animate */);
Adrian Roos34e65442014-05-17 02:35:33 +02003752 }
Adrian Roos217ccd22014-05-09 14:29:04 +02003753 }
3754
3755 @Override
3756 public int getNavigationBarColor() {
Adrian Roos34e65442014-05-17 02:35:33 +02003757 return mNavigationBarColor;
Adrian Roos217ccd22014-05-09 14:29:04 +02003758 }
3759
3760 @Override
3761 public void setNavigationBarColor(int color) {
Adrian Roos34e65442014-05-17 02:35:33 +02003762 mNavigationBarColor = color;
3763 mForcedNavigationBarColor = true;
3764 if (mDecor != null) {
Adrian Roos05054bd2014-10-27 17:04:10 +01003765 mDecor.updateColorViews(null, false /* animate */);
Seigo Nonaka0a9d1ea2015-11-18 22:29:06 +09003766 mDecor.updateNavigationGuardColor();
Adrian Roos34e65442014-05-17 02:35:33 +02003767 }
Adrian Roos217ccd22014-05-09 14:29:04 +02003768 }
Jorim Jaggia16cc152015-06-01 16:55:05 -07003769
3770 public void setIsStartingWindow(boolean isStartingWindow) {
3771 mIsStartingWindow = isStartingWindow;
3772 }
Stefan Kuhnef4dd71a2015-08-07 09:28:52 -07003773
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -07003774 @Override
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07003775 public void setTheme(int resid) {
3776 mTheme = resid;
3777 if (mDecor != null) {
3778 Context context = mDecor.getContext();
3779 if (context instanceof DecorContext) {
3780 context.setTheme(resid);
3781 }
3782 }
3783 }
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08003784
3785 @Override
3786 public void setResizingCaptionDrawable(Drawable drawable) {
3787 mDecor.setUserCaptionBackgroundDrawable(drawable);
3788 }
3789
3790 @Override
3791 public void setDecorCaptionShade(int decorCaptionShade) {
3792 mDecorCaptionShade = decorCaptionShade;
3793 if (mDecor != null) {
3794 mDecor.updateDecorCaptionShade();
3795 }
3796 }
3797
3798 int getDecorCaptionShade() {
3799 return mDecorCaptionShade;
3800 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003801
3802 @Override
3803 public void setAttributes(WindowManager.LayoutParams params) {
3804 super.setAttributes(params);
3805 if (mDecor != null) {
3806 mDecor.updateLogTag(params);
3807 }
3808 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003809}