blob: 794a6d67893665358858ff40013f2a063a48b5db [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
Adam Powell6711f3b2015-05-06 15:57:09 -070027import android.view.ContextThemeWrapper;
Adam Powell6711f3b2015-05-06 15:57:09 -070028import android.view.Gravity;
29import android.view.IRotationWatcher.Stub;
30import android.view.IWindowManager;
31import android.view.InputDevice;
32import android.view.InputEvent;
33import android.view.InputQueue;
34import android.view.KeyCharacterMap;
35import android.view.KeyEvent;
36import android.view.LayoutInflater;
37import android.view.Menu;
38import android.view.MenuItem;
39import android.view.MotionEvent;
40import android.view.SearchEvent;
41import android.view.SurfaceHolder.Callback2;
42import android.view.View;
43import android.view.ViewConfiguration;
44import android.view.ViewGroup;
45import android.view.ViewManager;
46import android.view.ViewParent;
47import android.view.ViewRootImpl;
Adam Powell6711f3b2015-05-06 15:57:09 -070048import android.view.Window;
Adam Powell6711f3b2015-05-06 15:57:09 -070049import android.view.WindowManager;
John Spurlockae3349e2013-10-18 17:34:42 -040050import com.android.internal.R;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080051import com.android.internal.view.menu.ContextMenuBuilder;
Adam Powell696cba52011-03-29 10:38:16 -070052import com.android.internal.view.menu.IconMenuPresenter;
Adam Powell640a66e2011-04-29 10:18:53 -070053import com.android.internal.view.menu.ListMenuPresenter;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080054import com.android.internal.view.menu.MenuBuilder;
55import com.android.internal.view.menu.MenuDialogHelper;
Alan Viverette021627e2015-11-25 14:22:00 -050056import com.android.internal.view.menu.MenuHelper;
Adam Powell696cba52011-03-29 10:38:16 -070057import com.android.internal.view.menu.MenuPresenter;
Adam Powell640a66e2011-04-29 10:18:53 -070058import com.android.internal.view.menu.MenuView;
Adam Powell4369e7d2014-05-17 14:16:08 -070059import com.android.internal.widget.DecorContentParent;
Will Haldean Brownca6234e2014-02-12 10:23:41 -080060import com.android.internal.widget.SwipeDismissLayout;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080061
Adrian Roosea562512014-05-05 13:33:03 +020062import android.app.ActivityManager;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080063import android.app.KeyguardManager;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080064import android.content.Context;
Tim Kilbourn0e5f1102015-06-05 16:18:09 -070065import android.content.Intent;
Aaron Whyte1fb617f2014-05-12 22:08:53 -070066import android.content.pm.PackageManager;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080067import android.content.res.Configuration;
Alan Viverette4b002d32014-06-03 17:32:19 -070068import android.content.res.Resources.Theme;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080069import android.content.res.TypedArray;
Adrian Roosea562512014-05-05 13:33:03 +020070import android.graphics.Color;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080071import android.graphics.drawable.Drawable;
72import android.media.AudioManager;
RoboErik55011652014-07-09 15:05:53 -070073import android.media.session.MediaController;
RoboErik55011652014-07-09 15:05:53 -070074import android.media.session.MediaSessionLegacyHelper;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080075import android.net.Uri;
76import android.os.Bundle;
Adam Powelldfee59a2011-08-05 20:48:30 -070077import android.os.Handler;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080078import android.os.Parcel;
79import android.os.Parcelable;
Adam Powelldfee59a2011-08-05 20:48:30 -070080import android.os.RemoteException;
81import android.os.ServiceManager;
George Mount31a21722014-03-24 17:44:36 -070082import android.transition.Scene;
83import android.transition.Transition;
84import android.transition.TransitionInflater;
85import android.transition.TransitionManager;
George Mount68f96d82014-07-31 13:13:10 -070086import android.transition.TransitionSet;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080087import android.util.AndroidRuntimeException;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080088import android.util.EventLog;
89import android.util.Log;
90import android.util.SparseArray;
Adam Powell85446e92010-10-22 17:43:56 -070091import android.util.TypedValue;
Alan Viveretteec6cf182015-08-13 15:31:57 -040092import android.view.accessibility.AccessibilityNodeInfo;
93import android.view.accessibility.AccessibilityNodeProvider;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080094import android.view.animation.Animation;
95import android.view.animation.AnimationUtils;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080096import android.widget.FrameLayout;
97import android.widget.ImageView;
98import android.widget.ProgressBar;
99import android.widget.TextView;
100
Adam Powelldfee59a2011-08-05 20:48:30 -0700101import java.lang.ref.WeakReference;
102import java.util.ArrayList;
103
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800104/**
105 * Android-specific Window.
106 * <p>
107 * todo: need to pull the generic functionality out into a base class
108 * in android.widget.
Jorim Jaggib10e33f2015-02-04 21:57:40 +0100109 *
110 * @hide
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800111 */
112public class PhoneWindow extends Window implements MenuBuilder.Callback {
svetoslavganov491293e2009-04-28 19:17:02 -0700113
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800114 private final static String TAG = "PhoneWindow";
115
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800116 private static final boolean DEBUG = false;
117
George Mounted1e01d2014-06-05 13:49:12 -0700118 private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300;
119
Adam Powell166c8e32014-07-01 17:37:48 -0700120 private static final int CUSTOM_TITLE_COMPATIBLE_FEATURES = DEFAULT_FEATURES |
121 (1 << FEATURE_CUSTOM_TITLE) |
122 (1 << FEATURE_CONTENT_TRANSITIONS) |
George Mount9826f632014-09-11 08:50:09 -0700123 (1 << FEATURE_ACTIVITY_TRANSITIONS) |
Adam Powell166c8e32014-07-01 17:37:48 -0700124 (1 << FEATURE_ACTION_MODE_OVERLAY);
125
George Mount68f96d82014-07-31 13:13:10 -0700126 private static final Transition USE_DEFAULT_TRANSITION = new TransitionSet();
127
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800128 /**
129 * Simple callback used by the context menu and its submenus. The options
130 * menu submenus do not use this (their behavior is more complex).
131 */
Alan Viverette77fb85e2015-12-14 11:42:44 -0500132 final PhoneWindowMenuCallback mContextMenuCallback = new PhoneWindowMenuCallback(this);
Dianne Hackborn60145272011-01-11 23:45:09 -0800133
134 final TypedValue mMinWidthMajor = new TypedValue();
135 final TypedValue mMinWidthMinor = new TypedValue();
Adam Powell40eec4c2012-02-15 17:10:58 -0800136 TypedValue mFixedWidthMajor;
137 TypedValue mFixedWidthMinor;
138 TypedValue mFixedHeightMajor;
139 TypedValue mFixedHeightMinor;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800140
141 // This is the top-level view of the window, containing the window decor.
142 private DecorView mDecor;
143
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700144 // When we reuse decor views, we need to recreate the content root. This happens when the decor
145 // view is requested, so we need to force the recreating without introducing an infinite loop.
146 private boolean mForceDecorInstall = false;
147
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800148 // This is the view in which the window contents are placed. It is either
149 // mDecor itself, or a child of mDecor where the contents go.
Wale Ogunwale8804af22015-11-17 09:18:15 -0800150 ViewGroup mContentParent;
Filip Gruszczynskif4bdaeb2016-01-06 14:34:00 -0800151 // Whether the client has explicitly set the content view. If false and mContentParent is not
152 // null, then the content parent was set due to window preservation.
153 private boolean mContentParentExplicitlySet = false;
Adrian Roosf5e9b5c2014-09-10 15:27:41 +0200154
Adam Powell6711f3b2015-05-06 15:57:09 -0700155 Callback2 mTakeSurfaceCallback;
George Mount0a778ed2013-12-13 13:35:36 -0800156
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700157 InputQueue.Callback mTakeInputQueueCallback;
George Mount0a778ed2013-12-13 13:35:36 -0800158
Wale Ogunwale8804af22015-11-17 09:18:15 -0800159 boolean mIsFloating;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700160 private boolean mIsTranslucent;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800161
162 private LayoutInflater mLayoutInflater;
163
164 private TextView mTitleView;
George Mount0a778ed2013-12-13 13:35:36 -0800165
Wale Ogunwale8804af22015-11-17 09:18:15 -0800166 DecorContentParent mDecorContentParent;
Adam Powell696cba52011-03-29 10:38:16 -0700167 private ActionMenuPresenterCallback mActionMenuPresenterCallback;
168 private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800169
Adam Powell18e905f2013-10-24 14:27:48 -0700170 private TransitionManager mTransitionManager;
Adam Powellcfbe9be2013-11-06 14:58:58 -0800171 private Scene mContentScene;
Adam Powell18e905f2013-10-24 14:27:48 -0700172
Adam Powell0a317e92013-06-13 13:15:43 -0700173 // The icon resource has been explicitly set elsewhere
174 // and should not be overwritten with a default.
Adam Powell04fe6eb2013-05-31 14:39:48 -0700175 static final int FLAG_RESOURCE_SET_ICON = 1 << 0;
Adam Powell0a317e92013-06-13 13:15:43 -0700176
177 // The logo resource has been explicitly set elsewhere
178 // and should not be overwritten with a default.
Adam Powell04fe6eb2013-05-31 14:39:48 -0700179 static final int FLAG_RESOURCE_SET_LOGO = 1 << 1;
Adam Powell0a317e92013-06-13 13:15:43 -0700180
181 // The icon resource is currently configured to use the system fallback
182 // as no default was previously specified. Anything can override this.
183 static final int FLAG_RESOURCE_SET_ICON_FALLBACK = 1 << 2;
184
Adam Powell04fe6eb2013-05-31 14:39:48 -0700185 int mResourcesSetFlags;
186 int mIconRes;
187 int mLogoRes;
188
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800189 private DrawableFeatureState[] mDrawables;
190
191 private PanelFeatureState[] mPanels;
192
193 /**
194 * The panel that is prepared or opened (the most recent one if there are
195 * multiple panels). Shortcuts will go to this panel. It gets set in
196 * {@link #preparePanel} and cleared in {@link #closePanel}.
197 */
Wale Ogunwale8804af22015-11-17 09:18:15 -0800198 PanelFeatureState mPreparedPanel;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800199
200 /**
201 * The keycode that is currently held down (as a modifier) for chording. If
202 * this is 0, there is no key held down.
203 */
Wale Ogunwale8804af22015-11-17 09:18:15 -0800204 int mPanelChordingKey;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800205
206 private ImageView mLeftIconView;
207
208 private ImageView mRightIconView;
209
210 private ProgressBar mCircularProgressBar;
211
212 private ProgressBar mHorizontalProgressBar;
213
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800214 int mBackgroundResource = 0;
215 int mBackgroundFallbackResource = 0;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800216
217 private Drawable mBackgroundDrawable;
218
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800219 private boolean mLoadElevation = true;
Alan Viverette49a22e82014-07-12 20:01:27 -0700220 private float mElevation;
221
Alan Viverette40982d42014-07-25 17:48:55 -0700222 /** Whether window content should be clipped to the background outline. */
223 private boolean mClipToOutline;
224
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800225 private int mFrameResource = 0;
226
227 private int mTextColor = 0;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800228 int mStatusBarColor = 0;
229 int mNavigationBarColor = 0;
Adrian Roos34e65442014-05-17 02:35:33 +0200230 private boolean mForcedStatusBarColor = false;
231 private boolean mForcedNavigationBarColor = false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800232
233 private CharSequence mTitle = null;
234
235 private int mTitleColor = 0;
236
Dianne Hackborncfaf8872011-01-18 13:57:54 -0800237 private boolean mAlwaysReadCloseOnTouchAttr = false;
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700238
Wale Ogunwale8804af22015-11-17 09:18:15 -0800239 ContextMenuBuilder mContextMenu;
Alan Viverette021627e2015-11-25 14:22:00 -0500240 MenuHelper mContextMenuHelper;
Adam Powell8515ee82010-11-30 14:09:55 -0800241 private boolean mClosingActionMenu;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800242
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800243 private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
RoboErik55011652014-07-09 15:05:53 -0700244 private MediaController mMediaController;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800245
Joe Onorato86f67862010-11-05 18:57:34 -0700246 private AudioManager mAudioManager;
247 private KeyguardManager mKeyguardManager;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800248
Adam Powell269248d2011-08-02 10:26:54 -0700249 private int mUiOptions = 0;
250
Adam Powell4b6d93f2012-09-18 18:34:08 -0700251 private boolean mInvalidatePanelMenuPosted;
252 private int mInvalidatePanelMenuFeatures;
253 private final Runnable mInvalidatePanelMenuRunnable = new Runnable() {
254 @Override public void run() {
255 for (int i = 0; i <= FEATURE_MAX; i++) {
256 if ((mInvalidatePanelMenuFeatures & 1 << i) != 0) {
257 doInvalidatePanelMenu(i);
258 }
259 }
260 mInvalidatePanelMenuPosted = false;
261 mInvalidatePanelMenuFeatures = 0;
262 }
263 };
264
George Mount68f96d82014-07-31 13:13:10 -0700265 private Transition mEnterTransition = null;
266 private Transition mReturnTransition = USE_DEFAULT_TRANSITION;
267 private Transition mExitTransition = null;
268 private Transition mReenterTransition = USE_DEFAULT_TRANSITION;
269 private Transition mSharedElementEnterTransition = null;
270 private Transition mSharedElementReturnTransition = USE_DEFAULT_TRANSITION;
271 private Transition mSharedElementExitTransition = null;
272 private Transition mSharedElementReenterTransition = USE_DEFAULT_TRANSITION;
George Mountc03da0e2014-08-22 17:04:02 -0700273 private Boolean mAllowReturnTransitionOverlap;
George Mount31a21722014-03-24 17:44:36 -0700274 private Boolean mAllowEnterTransitionOverlap;
George Mounted1e01d2014-06-05 13:49:12 -0700275 private long mBackgroundFadeDurationMillis = -1;
George Mountb89d5cc2014-08-18 16:50:50 -0700276 private Boolean mSharedElementsUseOverlay;
George Mount0a778ed2013-12-13 13:35:36 -0800277
Jorim Jaggia16cc152015-06-01 16:55:05 -0700278 private boolean mIsStartingWindow;
Filip Gruszczynski0daf2102015-09-29 08:39:07 -0700279 private int mTheme = -1;
Jorim Jaggia16cc152015-06-01 16:55:05 -0700280
Filip Gruszczynski3dec0812015-12-09 08:42:41 -0800281 private int mDecorCaptionShade = DECOR_CAPTION_SHADE_AUTO;
282
Filip Gruszczynski796b8c12015-12-22 14:46:21 -0800283 private boolean mUseDecorContext = false;
284
Adam Powelldfee59a2011-08-05 20:48:30 -0700285 static class WindowManagerHolder {
286 static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
287 ServiceManager.getService("window"));
288 }
289
290 static final RotationWatcher sRotationWatcher = new RotationWatcher();
291
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800292 public PhoneWindow(Context context) {
293 super(context);
294 mLayoutInflater = LayoutInflater.from(context);
295 }
296
Filip Gruszczynski796b8c12015-12-22 14:46:21 -0800297 /**
298 * Constructor for main window of an activity.
299 */
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700300 public PhoneWindow(Context context, Window preservedWindow) {
301 this(context);
Filip Gruszczynski796b8c12015-12-22 14:46:21 -0800302 // Only main activity windows use decor context, all the other windows depend on whatever
303 // context that was given to them.
304 mUseDecorContext = true;
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700305 if (preservedWindow != null) {
306 mDecor = (DecorView) preservedWindow.getDecorView();
307 mElevation = preservedWindow.getElevation();
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800308 mLoadElevation = false;
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700309 mForceDecorInstall = true;
Chong Zhanga8be1b92015-09-29 13:54:44 -0700310 // If we're preserving window, carry over the app token from the preserved
311 // window, as we'll be skipping the addView in handleResumeActivity(), and
312 // the token will not be updated as for a new window.
313 getAttributes().token = preservedWindow.getAttributes().token;
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700314 }
315 }
316
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800317 @Override
318 public final void setContainer(Window container) {
319 super.setContainer(container);
320 }
321
322 @Override
323 public boolean requestFeature(int featureId) {
Filip Gruszczynskif4bdaeb2016-01-06 14:34:00 -0800324 if (mContentParentExplicitlySet) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800325 throw new AndroidRuntimeException("requestFeature() must be called before adding content");
326 }
327 final int features = getFeatures();
Adam Powell166c8e32014-07-01 17:37:48 -0700328 final int newFeatures = features | (1 << featureId);
329 if ((newFeatures & (1 << FEATURE_CUSTOM_TITLE)) != 0 &&
330 (newFeatures & ~CUSTOM_TITLE_COMPATIBLE_FEATURES) != 0) {
331 // Another feature is enabled and the user is trying to enable the custom title feature
332 // or custom title feature is enabled and the user is trying to enable another feature
333 throw new AndroidRuntimeException(
334 "You cannot combine custom titles with other title features");
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800335 }
Adam Powellf4a6ec42010-08-24 14:18:10 -0700336 if ((features & (1 << FEATURE_NO_TITLE)) != 0 && featureId == FEATURE_ACTION_BAR) {
337 return false; // Ignore. No title dominates.
338 }
339 if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_NO_TITLE) {
340 // Remove the action bar feature if we have no title. No title dominates.
341 removeFeature(FEATURE_ACTION_BAR);
342 }
Will Haldean Brownca6234e2014-02-12 10:23:41 -0800343
344 if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_SWIPE_TO_DISMISS) {
345 throw new AndroidRuntimeException(
346 "You cannot combine swipe dismissal and the action bar.");
347 }
348 if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0 && featureId == FEATURE_ACTION_BAR) {
349 throw new AndroidRuntimeException(
350 "You cannot combine swipe dismissal and the action bar.");
351 }
Aaron Whyte1fb617f2014-05-12 22:08:53 -0700352
353 if (featureId == FEATURE_INDETERMINATE_PROGRESS &&
354 getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
355 throw new AndroidRuntimeException("You cannot use indeterminate progress on a watch.");
356 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800357 return super.requestFeature(featureId);
358 }
359
360 @Override
Adam Powell269248d2011-08-02 10:26:54 -0700361 public void setUiOptions(int uiOptions) {
362 mUiOptions = uiOptions;
363 }
364
365 @Override
Adam Powelle43fca92011-08-16 12:57:01 -0700366 public void setUiOptions(int uiOptions, int mask) {
367 mUiOptions = (mUiOptions & ~mask) | (uiOptions & mask);
368 }
369
370 @Override
Adam Powellcfbe9be2013-11-06 14:58:58 -0800371 public TransitionManager getTransitionManager() {
372 return mTransitionManager;
373 }
374
375 @Override
376 public void setTransitionManager(TransitionManager tm) {
377 mTransitionManager = tm;
378 }
379
380 @Override
381 public Scene getContentScene() {
382 return mContentScene;
383 }
384
385 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800386 public void setContentView(int layoutResID) {
Adam Powell18e905f2013-10-24 14:27:48 -0700387 // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
388 // decor, when theme attributes and the like are crystalized. Do not check the feature
389 // before this happens.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800390 if (mContentParent == null) {
391 installDecor();
Adam Powell18e905f2013-10-24 14:27:48 -0700392 } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800393 mContentParent.removeAllViews();
394 }
Adam Powell18e905f2013-10-24 14:27:48 -0700395
396 if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
397 final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
398 getContext());
Adam Powellcfbe9be2013-11-06 14:58:58 -0800399 transitionTo(newScene);
Adam Powell18e905f2013-10-24 14:27:48 -0700400 } else {
401 mLayoutInflater.inflate(layoutResID, mContentParent);
402 }
Adam Powell41607d52015-06-17 13:37:06 -0700403 mContentParent.requestApplyInsets();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800404 final Callback cb = getCallback();
Dianne Hackbornb66ad572011-03-01 17:10:30 -0800405 if (cb != null && !isDestroyed()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800406 cb.onContentChanged();
407 }
Filip Gruszczynskif4bdaeb2016-01-06 14:34:00 -0800408 mContentParentExplicitlySet = true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800409 }
410
411 @Override
412 public void setContentView(View view) {
Romain Guycc6828c2010-01-08 15:06:37 -0800413 setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800414 }
415
416 @Override
417 public void setContentView(View view, ViewGroup.LayoutParams params) {
Adam Powell18e905f2013-10-24 14:27:48 -0700418 // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
419 // decor, when theme attributes and the like are crystalized. Do not check the feature
420 // before this happens.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800421 if (mContentParent == null) {
422 installDecor();
Adam Powell18e905f2013-10-24 14:27:48 -0700423 } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800424 mContentParent.removeAllViews();
425 }
Adam Powell18e905f2013-10-24 14:27:48 -0700426
427 if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
428 view.setLayoutParams(params);
429 final Scene newScene = new Scene(mContentParent, view);
Adam Powellcfbe9be2013-11-06 14:58:58 -0800430 transitionTo(newScene);
Adam Powell18e905f2013-10-24 14:27:48 -0700431 } else {
432 mContentParent.addView(view, params);
433 }
Adam Powell41607d52015-06-17 13:37:06 -0700434 mContentParent.requestApplyInsets();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800435 final Callback cb = getCallback();
Dianne Hackbornb66ad572011-03-01 17:10:30 -0800436 if (cb != null && !isDestroyed()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800437 cb.onContentChanged();
438 }
Filip Gruszczynskif4bdaeb2016-01-06 14:34:00 -0800439 mContentParentExplicitlySet = true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800440 }
441
442 @Override
443 public void addContentView(View view, ViewGroup.LayoutParams params) {
444 if (mContentParent == null) {
445 installDecor();
446 }
Adam Powell18e905f2013-10-24 14:27:48 -0700447 if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
448 // TODO Augment the scenes/transitions API to support this.
George Mount7e208842014-07-02 07:22:43 -0700449 Log.v(TAG, "addContentView does not support content transitions");
Adam Powell18e905f2013-10-24 14:27:48 -0700450 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800451 mContentParent.addView(view, params);
Adam Powell41607d52015-06-17 13:37:06 -0700452 mContentParent.requestApplyInsets();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800453 final Callback cb = getCallback();
Dianne Hackbornb66ad572011-03-01 17:10:30 -0800454 if (cb != null && !isDestroyed()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800455 cb.onContentChanged();
456 }
457 }
458
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800459 @Override
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700460 public void clearContentView() {
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800461 if (mDecor != null) {
462 mDecor.clearContentView();
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -0700463 }
464 }
465
Adam Powellcfbe9be2013-11-06 14:58:58 -0800466 private void transitionTo(Scene scene) {
George Mount0a778ed2013-12-13 13:35:36 -0800467 if (mContentScene == null) {
468 scene.enter();
Adam Powellcfbe9be2013-11-06 14:58:58 -0800469 } else {
470 mTransitionManager.transitionTo(scene);
471 }
472 mContentScene = scene;
473 }
474
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800475 @Override
476 public View getCurrentFocus() {
477 return mDecor != null ? mDecor.findFocus() : null;
478 }
479
480 @Override
Adam Powell6711f3b2015-05-06 15:57:09 -0700481 public void takeSurface(Callback2 callback) {
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700482 mTakeSurfaceCallback = callback;
483 }
George Mount0a778ed2013-12-13 13:35:36 -0800484
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700485 public void takeInputQueue(InputQueue.Callback callback) {
486 mTakeInputQueueCallback = callback;
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700487 }
George Mount0a778ed2013-12-13 13:35:36 -0800488
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700489 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800490 public boolean isFloating() {
491 return mIsFloating;
492 }
493
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700494 public boolean isTranslucent() {
495 return mIsTranslucent;
496 }
497
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800498 /**
499 * Return a LayoutInflater instance that can be used to inflate XML view layout
500 * resources for use in this Window.
501 *
502 * @return LayoutInflater The shared LayoutInflater.
503 */
504 @Override
505 public LayoutInflater getLayoutInflater() {
506 return mLayoutInflater;
507 }
508
509 @Override
510 public void setTitle(CharSequence title) {
511 if (mTitleView != null) {
512 mTitleView.setText(title);
Adam Powell4369e7d2014-05-17 14:16:08 -0700513 } else if (mDecorContentParent != null) {
514 mDecorContentParent.setWindowTitle(title);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800515 }
516 mTitle = title;
517 }
518
519 @Override
Alan Viverette2525d9c2013-11-15 14:42:19 -0800520 @Deprecated
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800521 public void setTitleColor(int textColor) {
522 if (mTitleView != null) {
523 mTitleView.setTextColor(textColor);
524 }
525 mTitleColor = textColor;
526 }
527
528 /**
529 * Prepares the panel to either be opened or chorded. This creates the Menu
530 * instance for the panel and populates it via the Activity callbacks.
531 *
532 * @param st The panel state to prepare.
533 * @param event The event that triggered the preparing of the panel.
534 * @return Whether the panel was prepared. If the panel should not be shown,
535 * returns false.
536 */
537 public final boolean preparePanel(PanelFeatureState st, KeyEvent event) {
Dianne Hackbornb66ad572011-03-01 17:10:30 -0800538 if (isDestroyed()) {
539 return false;
540 }
541
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800542 // Already prepared (isPrepared will be reset to false later)
Adam Powellc6d51882011-10-13 11:33:24 -0700543 if (st.isPrepared) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800544 return true;
Adam Powellc6d51882011-10-13 11:33:24 -0700545 }
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700546
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800547 if ((mPreparedPanel != null) && (mPreparedPanel != st)) {
548 // Another Panel is prepared and possibly open, so close it
549 closePanel(mPreparedPanel, false);
550 }
551
552 final Callback cb = getCallback();
553
554 if (cb != null) {
555 st.createdPanelView = cb.onCreatePanelView(st.featureId);
556 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800557
Adam Powell8c16aa92013-04-04 10:47:52 -0700558 final boolean isActionBarMenu =
559 (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR);
560
Adam Powell4369e7d2014-05-17 14:16:08 -0700561 if (isActionBarMenu && mDecorContentParent != null) {
Adam Powell8c16aa92013-04-04 10:47:52 -0700562 // Enforce ordering guarantees around events so that the action bar never
563 // dispatches menu-related events before the panel is prepared.
Adam Powell4369e7d2014-05-17 14:16:08 -0700564 mDecorContentParent.setMenuPrepared();
Adam Powell8c16aa92013-04-04 10:47:52 -0700565 }
566
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800567 if (st.createdPanelView == null) {
568 // Init the panel state's menu--return false if init failed
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700569 if (st.menu == null || st.refreshMenuContent) {
570 if (st.menu == null) {
571 if (!initializePanelMenu(st) || (st.menu == null)) {
572 return false;
573 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800574 }
Adam Powell696cba52011-03-29 10:38:16 -0700575
Adam Powell4369e7d2014-05-17 14:16:08 -0700576 if (isActionBarMenu && mDecorContentParent != null) {
Adam Powellccdd4ee2011-07-27 20:05:14 -0700577 if (mActionMenuPresenterCallback == null) {
578 mActionMenuPresenterCallback = new ActionMenuPresenterCallback();
579 }
Adam Powell4369e7d2014-05-17 14:16:08 -0700580 mDecorContentParent.setMenu(st.menu, mActionMenuPresenterCallback);
Adam Powellccdd4ee2011-07-27 20:05:14 -0700581 }
582
Adam Powell696cba52011-03-29 10:38:16 -0700583 // Call callback, and return if it doesn't want to display menu.
584
585 // Creating the panel menu will involve a lot of manipulation;
586 // don't dispatch change events to presenters until we're done.
587 st.menu.stopDispatchingItemsChanged();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800588 if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) {
589 // Ditch the menu created above
Adam Powell1d07e162011-09-07 20:46:24 -0700590 st.setMenu(null);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800591
Adam Powell4369e7d2014-05-17 14:16:08 -0700592 if (isActionBarMenu && mDecorContentParent != null) {
Adam Powell84f49362011-08-18 11:09:57 -0700593 // Don't show it in the action bar either
Adam Powell4369e7d2014-05-17 14:16:08 -0700594 mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
Adam Powell84f49362011-08-18 11:09:57 -0700595 }
Adam Powellf35d0492011-08-17 13:56:47 -0700596
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800597 return false;
598 }
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700599
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700600 st.refreshMenuContent = false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800601 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800602
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800603 // Callback and return if the callback does not want to show the menu
Adam Powell696cba52011-03-29 10:38:16 -0700604
605 // Preparing the panel menu can involve a lot of manipulation;
606 // don't dispatch change events to presenters until we're done.
607 st.menu.stopDispatchingItemsChanged();
Adam Powell97a30012011-08-09 17:15:48 -0700608
609 // Restore action view state before we prepare. This gives apps
610 // an opportunity to override frozen/restored state in onPrepare.
611 if (st.frozenActionViewState != null) {
612 st.menu.restoreActionViewStates(st.frozenActionViewState);
613 st.frozenActionViewState = null;
614 }
615
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800616 if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) {
Adam Powell4369e7d2014-05-17 14:16:08 -0700617 if (isActionBarMenu && mDecorContentParent != null) {
Adam Powell84f49362011-08-18 11:09:57 -0700618 // The app didn't want to show the menu for now but it still exists.
619 // Clear it out of the action bar.
Adam Powell4369e7d2014-05-17 14:16:08 -0700620 mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
Adam Powell84f49362011-08-18 11:09:57 -0700621 }
Adam Powell696cba52011-03-29 10:38:16 -0700622 st.menu.startDispatchingItemsChanged();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800623 return false;
624 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800625
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800626 // Set the proper keymap
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800627 KeyCharacterMap kmap = KeyCharacterMap.load(
628 event != null ? event.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800629 st.qwertyMode = kmap.getKeyboardType() != KeyCharacterMap.NUMERIC;
630 st.menu.setQwertyMode(st.qwertyMode);
Adam Powell89b09da2011-07-27 11:55:29 -0700631 st.menu.startDispatchingItemsChanged();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800632 }
633
634 // Set other state
635 st.isPrepared = true;
636 st.isHandled = false;
637 mPreparedPanel = st;
638
639 return true;
640 }
641
642 @Override
643 public void onConfigurationChanged(Configuration newConfig) {
Adam Powell6c6f5752010-08-20 18:34:46 -0700644 // Action bars handle their own menu state
Adam Powell4369e7d2014-05-17 14:16:08 -0700645 if (mDecorContentParent == null) {
Adam Powell6c6f5752010-08-20 18:34:46 -0700646 PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
647 if ((st != null) && (st.menu != null)) {
Adam Powell6c6f5752010-08-20 18:34:46 -0700648 if (st.isOpen) {
649 // Freeze state
650 final Bundle state = new Bundle();
Adam Powell696cba52011-03-29 10:38:16 -0700651 if (st.iconMenuPresenter != null) {
652 st.iconMenuPresenter.saveHierarchyState(state);
653 }
Adam Powelldfee59a2011-08-05 20:48:30 -0700654 if (st.listMenuPresenter != null) {
655 st.listMenuPresenter.saveHierarchyState(state);
Adam Powell696cba52011-03-29 10:38:16 -0700656 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800657
Adam Powell6c6f5752010-08-20 18:34:46 -0700658 // Remove the menu views since they need to be recreated
659 // according to the new configuration
660 clearMenuViews(st);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800661
Adam Powell6c6f5752010-08-20 18:34:46 -0700662 // Re-open the same menu
663 reopenMenu(false);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800664
Adam Powell6c6f5752010-08-20 18:34:46 -0700665 // Restore state
Adam Powell696cba52011-03-29 10:38:16 -0700666 if (st.iconMenuPresenter != null) {
667 st.iconMenuPresenter.restoreHierarchyState(state);
668 }
Adam Powelldfee59a2011-08-05 20:48:30 -0700669 if (st.listMenuPresenter != null) {
670 st.listMenuPresenter.restoreHierarchyState(state);
Adam Powell696cba52011-03-29 10:38:16 -0700671 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800672
Adam Powell6c6f5752010-08-20 18:34:46 -0700673 } else {
674 // Clear menu views so on next menu opening, it will use
675 // the proper layout
676 clearMenuViews(st);
677 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800678 }
679 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800680 }
681
Wale Ogunwaleeb6722c2015-12-08 11:43:43 -0800682 @Override
Wale Ogunwale3b93a4d2016-01-29 17:46:53 -0800683 public void onMultiWindowChanged() {
Wale Ogunwaleeb6722c2015-12-08 11:43:43 -0800684 if (mDecor != null) {
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -0800685 mDecor.onConfigurationChanged(getContext().getResources().getConfiguration());
Wale Ogunwaleeb6722c2015-12-08 11:43:43 -0800686 }
687 }
688
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100689 @Override
690 public void reportActivityRelaunched() {
691 if (mDecor != null && mDecor.getViewRootImpl() != null) {
692 mDecor.getViewRootImpl().reportActivityRelaunched();
693 }
694 }
695
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800696 private static void clearMenuViews(PanelFeatureState st) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800697 // This can be called on config changes, so we should make sure
698 // the views will be reconstructed based on the new orientation, etc.
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800699
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800700 // Allow the callback to create a new panel view
701 st.createdPanelView = null;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800702
703 // Causes the decor view to be recreated
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800704 st.refreshDecorView = true;
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700705
Adam Powell696cba52011-03-29 10:38:16 -0700706 st.clearMenuPresenters();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800707 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800708
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800709 @Override
710 public final void openPanel(int featureId, KeyEvent event) {
Adam Powell4369e7d2014-05-17 14:16:08 -0700711 if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
712 mDecorContentParent.canShowOverflowMenu() &&
Adam Powell5fcf5b92013-09-11 08:45:36 -0700713 !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
Adam Powell4369e7d2014-05-17 14:16:08 -0700714 mDecorContentParent.showOverflowMenu();
Adam Powellf75eeb22010-08-10 15:59:40 -0700715 } else {
716 openPanel(getPanelState(featureId, true), event);
717 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800718 }
719
Adam Powell5fcf5b92013-09-11 08:45:36 -0700720 private void openPanel(final PanelFeatureState st, KeyEvent event) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800721 // System.out.println("Open panel: isOpen=" + st.isOpen);
722
723 // Already open, return
Dianne Hackbornb66ad572011-03-01 17:10:30 -0800724 if (st.isOpen || isDestroyed()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800725 return;
726 }
727
Adam Powell0d69fae2011-01-08 15:07:08 -0800728 // Don't open an options panel for honeycomb apps on xlarge devices.
729 // (The app should be using an action bar for menu items.)
730 if (st.featureId == FEATURE_OPTIONS_PANEL) {
731 Context context = getContext();
732 Configuration config = context.getResources().getConfiguration();
733 boolean isXLarge = (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) ==
734 Configuration.SCREENLAYOUT_SIZE_XLARGE;
735 boolean isHoneycombApp = context.getApplicationInfo().targetSdkVersion >=
736 android.os.Build.VERSION_CODES.HONEYCOMB;
737
738 if (isXLarge && isHoneycombApp) {
739 return;
740 }
741 }
742
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800743 Callback cb = getCallback();
744 if ((cb != null) && (!cb.onMenuOpened(st.featureId, st.menu))) {
745 // Callback doesn't want the menu to open, reset any state
746 closePanel(st, true);
747 return;
748 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800749
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800750 final WindowManager wm = getWindowManager();
751 if (wm == null) {
752 return;
753 }
754
755 // Prepare panel (should have been done before, but just in case)
756 if (!preparePanel(st, event)) {
757 return;
758 }
759
Adam Powella3e3c532011-06-22 11:21:54 -0700760 int width = WRAP_CONTENT;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800761 if (st.decorView == null || st.refreshDecorView) {
762 if (st.decorView == null) {
763 // Initialize the panel decor, this will populate st.decorView
764 if (!initializePanelDecor(st) || (st.decorView == null))
765 return;
766 } else if (st.refreshDecorView && (st.decorView.getChildCount() > 0)) {
767 // Decor needs refreshing, so remove its views
768 st.decorView.removeAllViews();
769 }
770
771 // This will populate st.shownPanelView
Adam Powell526b9312011-04-22 15:42:05 -0700772 if (!initializePanelContent(st) || !st.hasPanelItems()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800773 return;
774 }
775
776 ViewGroup.LayoutParams lp = st.shownPanelView.getLayoutParams();
777 if (lp == null) {
778 lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
779 }
780
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800781 int backgroundResId;
Romain Guycc6828c2010-01-08 15:06:37 -0800782 if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800783 // If the contents is fill parent for the width, set the
784 // corresponding background
785 backgroundResId = st.fullBackground;
Adam Powella3e3c532011-06-22 11:21:54 -0700786 width = MATCH_PARENT;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800787 } else {
788 // Otherwise, set the normal panel background
789 backgroundResId = st.background;
790 }
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800791 st.decorView.setWindowBackground(getContext().getDrawable(
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800792 backgroundResId));
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800793
Adam Powella60314c2012-05-15 14:33:13 -0700794 ViewParent shownPanelParent = st.shownPanelView.getParent();
795 if (shownPanelParent != null && shownPanelParent instanceof ViewGroup) {
796 ((ViewGroup) shownPanelParent).removeView(st.shownPanelView);
797 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800798 st.decorView.addView(st.shownPanelView, lp);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800799
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800800 /*
801 * Give focus to the view, if it or one of its children does not
802 * already have it.
803 */
804 if (!st.shownPanelView.hasFocus()) {
805 st.shownPanelView.requestFocus();
806 }
Adam Powelldfee59a2011-08-05 20:48:30 -0700807 } else if (!st.isInListMode()) {
Adam Powelldc5facd2011-08-03 16:45:45 -0700808 width = MATCH_PARENT;
Adam Powell3429ff52011-08-18 18:32:48 -0700809 } else if (st.createdPanelView != null) {
810 // If we already had a panel view, carry width=MATCH_PARENT through
811 // as we did above when it was created.
812 ViewGroup.LayoutParams lp = st.createdPanelView.getLayoutParams();
813 if (lp != null && lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
814 width = MATCH_PARENT;
815 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800816 }
817
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800818 st.isHandled = false;
819
820 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
Adam Powella3e3c532011-06-22 11:21:54 -0700821 width, WRAP_CONTENT,
Dianne Hackbornd3715102009-09-15 19:28:03 -0700822 st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG,
Jeff Brown3cc321e2012-07-16 16:04:23 -0700823 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
Jeff Brown46e75292010-11-10 16:53:45 -0800824 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800825 st.decorView.mDefaultOpacity);
826
Adam Powelldfee59a2011-08-05 20:48:30 -0700827 if (st.isCompact) {
828 lp.gravity = getOptionsPanelGravity();
829 sRotationWatcher.addWindow(this);
830 } else {
831 lp.gravity = st.gravity;
832 }
833
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800834 lp.windowAnimations = st.windowAnimations;
Craig Mautner9b407282013-07-01 12:57:51 -0700835
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800836 wm.addView(st.decorView, lp);
Craig Mautner9b407282013-07-01 12:57:51 -0700837 st.isOpen = true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800838 // Log.v(TAG, "Adding main menu to window manager.");
839 }
840
841 @Override
842 public final void closePanel(int featureId) {
Adam Powell4369e7d2014-05-17 14:16:08 -0700843 if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
844 mDecorContentParent.canShowOverflowMenu() &&
Adam Powell5fcf5b92013-09-11 08:45:36 -0700845 !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
Adam Powell4369e7d2014-05-17 14:16:08 -0700846 mDecorContentParent.hideOverflowMenu();
Adam Powellf75eeb22010-08-10 15:59:40 -0700847 } else if (featureId == FEATURE_CONTEXT_MENU) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800848 closeContextMenu();
849 } else {
850 closePanel(getPanelState(featureId, true), true);
851 }
852 }
853
854 /**
855 * Closes the given panel.
856 *
857 * @param st The panel to be closed.
858 * @param doCallback Whether to notify the callback that the panel was
859 * closed. If the panel is in the process of re-opening or
860 * opening another panel (e.g., menu opening a sub menu), the
861 * callback should not happen and this variable should be false.
862 * In addition, this method internally will only perform the
863 * callback if the panel is open.
864 */
865 public final void closePanel(PanelFeatureState st, boolean doCallback) {
866 // System.out.println("Close panel: isOpen=" + st.isOpen);
Adam Powell696cba52011-03-29 10:38:16 -0700867 if (doCallback && st.featureId == FEATURE_OPTIONS_PANEL &&
Adam Powell4369e7d2014-05-17 14:16:08 -0700868 mDecorContentParent != null && mDecorContentParent.isOverflowMenuShowing()) {
Adam Powell696cba52011-03-29 10:38:16 -0700869 checkCloseActionMenu(st.menu);
870 return;
871 }
872
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800873 final ViewManager wm = getWindowManager();
874 if ((wm != null) && st.isOpen) {
875 if (st.decorView != null) {
876 wm.removeView(st.decorView);
877 // Log.v(TAG, "Removing main menu from window manager.");
Adam Powelldfee59a2011-08-05 20:48:30 -0700878 if (st.isCompact) {
879 sRotationWatcher.removeWindow(this);
880 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800881 }
882
883 if (doCallback) {
884 callOnPanelClosed(st.featureId, st, null);
885 }
886 }
Adam Powell696cba52011-03-29 10:38:16 -0700887
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800888 st.isPrepared = false;
889 st.isHandled = false;
890 st.isOpen = false;
891
892 // This view is no longer shown, so null it out
893 st.shownPanelView = null;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -0800894
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800895 if (st.isInExpandedMode) {
896 // Next time the menu opens, it should not be in expanded mode, so
897 // force a refresh of the decor
898 st.refreshDecorView = true;
899 st.isInExpandedMode = false;
900 }
901
902 if (mPreparedPanel == st) {
903 mPreparedPanel = null;
904 mPanelChordingKey = 0;
905 }
906 }
907
Adam Powell640a66e2011-04-29 10:18:53 -0700908 void checkCloseActionMenu(Menu menu) {
Adam Powell8515ee82010-11-30 14:09:55 -0800909 if (mClosingActionMenu) {
910 return;
911 }
912
Adam Powell8515ee82010-11-30 14:09:55 -0800913 mClosingActionMenu = true;
Adam Powell4369e7d2014-05-17 14:16:08 -0700914 mDecorContentParent.dismissPopups();
Adam Powell8515ee82010-11-30 14:09:55 -0800915 Callback cb = getCallback();
Adam Powell696cba52011-03-29 10:38:16 -0700916 if (cb != null && !isDestroyed()) {
Adam Powell8515ee82010-11-30 14:09:55 -0800917 cb.onPanelClosed(FEATURE_ACTION_BAR, menu);
918 }
919 mClosingActionMenu = false;
920 }
921
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800922 @Override
923 public final void togglePanel(int featureId, KeyEvent event) {
924 PanelFeatureState st = getPanelState(featureId, true);
925 if (st.isOpen) {
926 closePanel(st, true);
927 } else {
928 openPanel(st, event);
929 }
930 }
931
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700932 @Override
933 public void invalidatePanelMenu(int featureId) {
Adam Powell4b6d93f2012-09-18 18:34:08 -0700934 mInvalidatePanelMenuFeatures |= 1 << featureId;
935
936 if (!mInvalidatePanelMenuPosted && mDecor != null) {
937 mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
938 mInvalidatePanelMenuPosted = true;
939 }
940 }
941
Adam Powell31c91c82014-08-22 17:20:00 -0700942 void doPendingInvalidatePanelMenu() {
943 if (mInvalidatePanelMenuPosted) {
944 mDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
945 mInvalidatePanelMenuRunnable.run();
946 }
947 }
948
Adam Powell4b6d93f2012-09-18 18:34:08 -0700949 void doInvalidatePanelMenu(int featureId) {
Jose Lima7a22fc62015-01-23 17:24:22 -0800950 PanelFeatureState st = getPanelState(featureId, false);
951 if (st == null) {
952 return;
953 }
Adam Powell038f1c82011-07-21 14:28:10 -0700954 Bundle savedActionViewStates = null;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700955 if (st.menu != null) {
Adam Powell038f1c82011-07-21 14:28:10 -0700956 savedActionViewStates = new Bundle();
957 st.menu.saveActionViewStates(savedActionViewStates);
958 if (savedActionViewStates.size() > 0) {
959 st.frozenActionViewState = savedActionViewStates;
960 }
Adam Powell89b09da2011-07-27 11:55:29 -0700961 // This will be started again when the panel is prepared.
962 st.menu.stopDispatchingItemsChanged();
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700963 st.menu.clear();
964 }
965 st.refreshMenuContent = true;
966 st.refreshDecorView = true;
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700967
Adam Powell96675b12010-06-10 18:58:59 -0700968 // Prepare the options panel if we have an action bar
969 if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL)
Adam Powell4369e7d2014-05-17 14:16:08 -0700970 && mDecorContentParent != null) {
Adam Powell96675b12010-06-10 18:58:59 -0700971 st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
972 if (st != null) {
973 st.isPrepared = false;
974 preparePanel(st, null);
975 }
976 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700977 }
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700978
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800979 /**
980 * Called when the panel key is pushed down.
981 * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
982 * @param event The key event.
983 * @return Whether the key was handled.
984 */
985 public final boolean onKeyDownPanel(int featureId, KeyEvent event) {
Dianne Hackborna207baa2009-09-13 16:14:44 -0700986 final int keyCode = event.getKeyCode();
Alan Viveretteeb1d3792014-06-03 18:36:03 -0700987
Dianne Hackborna207baa2009-09-13 16:14:44 -0700988 if (event.getRepeatCount() == 0) {
989 // The panel key was pushed, so set the chording key
990 mPanelChordingKey = keyCode;
Adam Powellf6148c52010-08-11 21:10:16 -0700991
Jose Lima7a22fc62015-01-23 17:24:22 -0800992 PanelFeatureState st = getPanelState(featureId, false);
993 if (st != null && !st.isOpen) {
Dianne Hackborna207baa2009-09-13 16:14:44 -0700994 return preparePanel(st, event);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800995 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800996 }
997
998 return false;
999 }
1000
1001 /**
1002 * Called when the panel key is released.
1003 * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
1004 * @param event The key event.
1005 */
1006 public final void onKeyUpPanel(int featureId, KeyEvent event) {
1007 // The panel key was released, so clear the chording key
1008 if (mPanelChordingKey != 0) {
1009 mPanelChordingKey = 0;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001010
Jose Lima7a22fc62015-01-23 17:24:22 -08001011 final PanelFeatureState st = getPanelState(featureId, false);
1012
Clara Bayarri80c38562015-03-04 17:10:57 +00001013 if (event.isCanceled() || (mDecor != null && mDecor.mPrimaryActionMode != null) ||
Jose Lima7a22fc62015-01-23 17:24:22 -08001014 (st == null)) {
Dianne Hackborn0041e972009-07-24 17:14:43 -07001015 return;
1016 }
Alan Viveretteeb1d3792014-06-03 18:36:03 -07001017
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001018 boolean playSoundEffect = false;
Adam Powell4369e7d2014-05-17 14:16:08 -07001019 if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
1020 mDecorContentParent.canShowOverflowMenu() &&
Adam Powell5fcf5b92013-09-11 08:45:36 -07001021 !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
Adam Powell4369e7d2014-05-17 14:16:08 -07001022 if (!mDecorContentParent.isOverflowMenuShowing()) {
1023 if (!isDestroyed() && preparePanel(st, event)) {
1024 playSoundEffect = mDecorContentParent.showOverflowMenu();
Adam Powellf6148c52010-08-11 21:10:16 -07001025 }
Adam Powell4369e7d2014-05-17 14:16:08 -07001026 } else {
1027 playSoundEffect = mDecorContentParent.hideOverflowMenu();
Adam Powellf6148c52010-08-11 21:10:16 -07001028 }
1029 } else {
1030 if (st.isOpen || st.isHandled) {
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001031
Adam Powellf6148c52010-08-11 21:10:16 -07001032 // Play the sound effect if the user closed an open menu (and not if
1033 // they just released a menu shortcut)
1034 playSoundEffect = st.isOpen;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001035
Adam Powellf6148c52010-08-11 21:10:16 -07001036 // Close menu
1037 closePanel(st, true);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001038
Adam Powellf6148c52010-08-11 21:10:16 -07001039 } else if (st.isPrepared) {
Adam Powellc6d51882011-10-13 11:33:24 -07001040 boolean show = true;
1041 if (st.refreshMenuContent) {
1042 // Something may have invalidated the menu since we prepared it.
1043 // Re-prepare it to refresh.
1044 st.isPrepared = false;
1045 show = preparePanel(st, event);
1046 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001047
Adam Powellc6d51882011-10-13 11:33:24 -07001048 if (show) {
1049 // Write 'menu opened' to event log
1050 EventLog.writeEvent(50001, 0);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001051
Adam Powellc6d51882011-10-13 11:33:24 -07001052 // Show menu
1053 openPanel(st, event);
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001054
Adam Powellc6d51882011-10-13 11:33:24 -07001055 playSoundEffect = true;
1056 }
Adam Powellf6148c52010-08-11 21:10:16 -07001057 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001058 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001059
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001060 if (playSoundEffect) {
1061 AudioManager audioManager = (AudioManager) getContext().getSystemService(
1062 Context.AUDIO_SERVICE);
1063 if (audioManager != null) {
1064 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
1065 } else {
1066 Log.w(TAG, "Couldn't get audio manager");
1067 }
1068 }
1069 }
1070 }
1071
1072 @Override
1073 public final void closeAllPanels() {
1074 final ViewManager wm = getWindowManager();
1075 if (wm == null) {
1076 return;
1077 }
1078
1079 final PanelFeatureState[] panels = mPanels;
1080 final int N = panels != null ? panels.length : 0;
1081 for (int i = 0; i < N; i++) {
1082 final PanelFeatureState panel = panels[i];
1083 if (panel != null) {
1084 closePanel(panel, true);
1085 }
1086 }
1087
1088 closeContextMenu();
1089 }
1090
1091 /**
1092 * Closes the context menu. This notifies the menu logic of the close, along
1093 * with dismissing it from the UI.
1094 */
1095 private synchronized void closeContextMenu() {
1096 if (mContextMenu != null) {
1097 mContextMenu.close();
1098 dismissContextMenu();
1099 }
1100 }
1101
1102 /**
1103 * Dismisses just the context menu UI. To close the context menu, use
1104 * {@link #closeContextMenu()}.
1105 */
1106 private synchronized void dismissContextMenu() {
1107 mContextMenu = null;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001108
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001109 if (mContextMenuHelper != null) {
1110 mContextMenuHelper.dismiss();
1111 mContextMenuHelper = null;
1112 }
1113 }
1114
1115 @Override
1116 public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
Jose Lima7a22fc62015-01-23 17:24:22 -08001117 return performPanelShortcut(getPanelState(featureId, false), keyCode, event, flags);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001118 }
1119
Wale Ogunwale8804af22015-11-17 09:18:15 -08001120 boolean performPanelShortcut(PanelFeatureState st, int keyCode, KeyEvent event,
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001121 int flags) {
1122 if (event.isSystem() || (st == null)) {
1123 return false;
1124 }
1125
1126 boolean handled = false;
1127
1128 // Only try to perform menu shortcuts if preparePanel returned true (possible false
1129 // return value from application not wanting to show the menu).
1130 if ((st.isPrepared || preparePanel(st, event)) && st.menu != null) {
1131 // The menu is prepared now, perform the shortcut on it
1132 handled = st.menu.performShortcut(keyCode, event, flags);
1133 }
1134
1135 if (handled) {
1136 // Mark as handled
1137 st.isHandled = true;
1138
Adam Powell6055f3e2011-08-28 14:20:24 -07001139 // Only close down the menu if we don't have an action bar keeping it open.
Adam Powell4369e7d2014-05-17 14:16:08 -07001140 if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0 && mDecorContentParent == null) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001141 closePanel(st, true);
1142 }
1143 }
1144
1145 return handled;
1146 }
1147
1148 @Override
1149 public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
1150
1151 PanelFeatureState st = getPanelState(featureId, true);
1152 if (!preparePanel(st, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU))) {
1153 return false;
1154 }
1155 if (st.menu == null) {
1156 return false;
1157 }
1158
1159 boolean res = st.menu.performIdentifierAction(id, flags);
1160
Adam Powell6055f3e2011-08-28 14:20:24 -07001161 // Only close down the menu if we don't have an action bar keeping it open.
Adam Powell4369e7d2014-05-17 14:16:08 -07001162 if (mDecorContentParent == null) {
Adam Powell6055f3e2011-08-28 14:20:24 -07001163 closePanel(st, true);
1164 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001165
1166 return res;
1167 }
1168
1169 public PanelFeatureState findMenuPanel(Menu menu) {
1170 final PanelFeatureState[] panels = mPanels;
1171 final int N = panels != null ? panels.length : 0;
1172 for (int i = 0; i < N; i++) {
1173 final PanelFeatureState panel = panels[i];
1174 if (panel != null && panel.menu == menu) {
1175 return panel;
1176 }
1177 }
1178 return null;
1179 }
1180
1181 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
1182 final Callback cb = getCallback();
Dianne Hackbornb66ad572011-03-01 17:10:30 -08001183 if (cb != null && !isDestroyed()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001184 final PanelFeatureState panel = findMenuPanel(menu.getRootMenu());
1185 if (panel != null) {
1186 return cb.onMenuItemSelected(panel.featureId, item);
1187 }
1188 }
1189 return false;
1190 }
1191
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001192 public void onMenuModeChange(MenuBuilder menu) {
1193 reopenMenu(true);
1194 }
1195
1196 private void reopenMenu(boolean toggleMenuMode) {
Adam Powell4369e7d2014-05-17 14:16:08 -07001197 if (mDecorContentParent != null && mDecorContentParent.canShowOverflowMenu() &&
Adam Powell5fcf5b92013-09-11 08:45:36 -07001198 (!ViewConfiguration.get(getContext()).hasPermanentMenuKey() ||
Adam Powell4369e7d2014-05-17 14:16:08 -07001199 mDecorContentParent.isOverflowMenuShowPending())) {
Adam Powell8515ee82010-11-30 14:09:55 -08001200 final Callback cb = getCallback();
Adam Powell4369e7d2014-05-17 14:16:08 -07001201 if (!mDecorContentParent.isOverflowMenuShowing() || !toggleMenuMode) {
1202 if (cb != null && !isDestroyed()) {
Adam Powell5c8f9b52013-03-27 12:22:27 -07001203 // If we have a menu invalidation pending, do it now.
1204 if (mInvalidatePanelMenuPosted &&
1205 (mInvalidatePanelMenuFeatures & (1 << FEATURE_OPTIONS_PANEL)) != 0) {
1206 mDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
1207 mInvalidatePanelMenuRunnable.run();
1208 }
1209
Jose Lima7a22fc62015-01-23 17:24:22 -08001210 final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
Adam Powell6a5b0a32012-09-28 14:24:48 -07001211
1212 // If we don't have a menu or we're waiting for a full content refresh,
1213 // forget it. This is a lingering event that no longer matters.
Jose Lima7a22fc62015-01-23 17:24:22 -08001214 if (st != null && st.menu != null && !st.refreshMenuContent &&
Adam Powell6a5b0a32012-09-28 14:24:48 -07001215 cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
Adam Powell8515ee82010-11-30 14:09:55 -08001216 cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
Adam Powell4369e7d2014-05-17 14:16:08 -07001217 mDecorContentParent.showOverflowMenu();
Adam Powellf6148c52010-08-11 21:10:16 -07001218 }
1219 }
1220 } else {
Adam Powell4369e7d2014-05-17 14:16:08 -07001221 mDecorContentParent.hideOverflowMenu();
Jose Lima7a22fc62015-01-23 17:24:22 -08001222 final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
1223 if (st != null && cb != null && !isDestroyed()) {
Adam Powell8515ee82010-11-30 14:09:55 -08001224 cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu);
1225 }
Adam Powellf6148c52010-08-11 21:10:16 -07001226 }
1227 return;
1228 }
1229
Jose Lima7a22fc62015-01-23 17:24:22 -08001230 PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
1231
1232 if (st == null) {
1233 return;
1234 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001235
1236 // Save the future expanded mode state since closePanel will reset it
1237 boolean newExpandedMode = toggleMenuMode ? !st.isInExpandedMode : st.isInExpandedMode;
1238
1239 st.refreshDecorView = true;
1240 closePanel(st, false);
1241
1242 // Set the expanded mode state
1243 st.isInExpandedMode = newExpandedMode;
1244
1245 openPanel(st, null);
1246 }
1247
1248 /**
1249 * Initializes the menu associated with the given panel feature state. You
1250 * must at the very least set PanelFeatureState.menu to the Menu to be
1251 * associated with the given panel state. The default implementation creates
1252 * a new menu for the panel state.
1253 *
1254 * @param st The panel whose menu is being initialized.
1255 * @return Whether the initialization was successful.
1256 */
1257 protected boolean initializePanelMenu(final PanelFeatureState st) {
Adam Powelld65b3b92011-09-22 16:38:11 -07001258 Context context = getContext();
1259
Alan Viveretteeb1d3792014-06-03 18:36:03 -07001260 // If we have an action bar, initialize the menu with the right theme.
Adam Powelld65b3b92011-09-22 16:38:11 -07001261 if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR) &&
Adam Powell4369e7d2014-05-17 14:16:08 -07001262 mDecorContentParent != null) {
Alan Viverette4b002d32014-06-03 17:32:19 -07001263 final TypedValue outValue = new TypedValue();
1264 final Theme baseTheme = context.getTheme();
Alan Viverette40982d42014-07-25 17:48:55 -07001265 baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
Adam Powelld65b3b92011-09-22 16:38:11 -07001266
Alan Viverette4b002d32014-06-03 17:32:19 -07001267 Theme widgetTheme = null;
1268 if (outValue.resourceId != 0) {
1269 widgetTheme = context.getResources().newTheme();
1270 widgetTheme.setTo(baseTheme);
1271 widgetTheme.applyStyle(outValue.resourceId, true);
1272 widgetTheme.resolveAttribute(
Alan Viverette40982d42014-07-25 17:48:55 -07001273 R.attr.actionBarWidgetTheme, outValue, true);
Alan Viverette4b002d32014-06-03 17:32:19 -07001274 } else {
1275 baseTheme.resolveAttribute(
Alan Viverette40982d42014-07-25 17:48:55 -07001276 R.attr.actionBarWidgetTheme, outValue, true);
Alan Viverette4b002d32014-06-03 17:32:19 -07001277 }
1278
1279 if (outValue.resourceId != 0) {
1280 if (widgetTheme == null) {
1281 widgetTheme = context.getResources().newTheme();
1282 widgetTheme.setTo(baseTheme);
1283 }
1284 widgetTheme.applyStyle(outValue.resourceId, true);
1285 }
1286
1287 if (widgetTheme != null) {
1288 context = new ContextThemeWrapper(context, 0);
1289 context.getTheme().setTo(widgetTheme);
Adam Powelld65b3b92011-09-22 16:38:11 -07001290 }
1291 }
1292
1293 final MenuBuilder menu = new MenuBuilder(context);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001294 menu.setCallback(this);
1295 st.setMenu(menu);
1296
1297 return true;
1298 }
1299
1300 /**
1301 * Perform initial setup of a panel. This should at the very least set the
1302 * style information in the PanelFeatureState and must set
1303 * PanelFeatureState.decor to the panel's window decor view.
1304 *
1305 * @param st The panel being initialized.
1306 */
1307 protected boolean initializePanelDecor(PanelFeatureState st) {
Stefan Kuhne61b47bb2015-07-28 14:04:25 -07001308 st.decorView = generateDecor(st.featureId);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001309 st.gravity = Gravity.CENTER | Gravity.BOTTOM;
1310 st.setStyle(getContext());
Adam Powell594558d2014-09-18 18:22:29 -07001311 TypedArray a = getContext().obtainStyledAttributes(null,
1312 R.styleable.Window, 0, st.listPresenterTheme);
1313 final float elevation = a.getDimension(R.styleable.Window_windowElevation, 0);
1314 if (elevation != 0) {
1315 st.decorView.setElevation(elevation);
1316 }
1317 a.recycle();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001318
1319 return true;
1320 }
1321
1322 /**
Adam Powelldfee59a2011-08-05 20:48:30 -07001323 * Determine the gravity value for the options panel. This can
1324 * differ in compact mode.
1325 *
1326 * @return gravity value to use for the panel window
1327 */
1328 private int getOptionsPanelGravity() {
1329 try {
1330 return WindowManagerHolder.sWindowManager.getPreferredOptionsPanelGravity();
1331 } catch (RemoteException ex) {
1332 Log.e(TAG, "Couldn't getOptionsPanelGravity; using default", ex);
1333 return Gravity.CENTER | Gravity.BOTTOM;
1334 }
1335 }
1336
1337 void onOptionsPanelRotationChanged() {
1338 final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
1339 if (st == null) return;
1340
1341 final WindowManager.LayoutParams lp = st.decorView != null ?
1342 (WindowManager.LayoutParams) st.decorView.getLayoutParams() : null;
1343 if (lp != null) {
1344 lp.gravity = getOptionsPanelGravity();
1345 final ViewManager wm = getWindowManager();
1346 if (wm != null) {
1347 wm.updateViewLayout(st.decorView, lp);
1348 }
1349 }
1350 }
1351
1352 /**
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001353 * Initializes the panel associated with the panel feature state. You must
1354 * at the very least set PanelFeatureState.panel to the View implementing
1355 * its contents. The default implementation gets the panel from the menu.
1356 *
1357 * @param st The panel state being initialized.
1358 * @return Whether the initialization was successful.
1359 */
1360 protected boolean initializePanelContent(PanelFeatureState st) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001361 if (st.createdPanelView != null) {
1362 st.shownPanelView = st.createdPanelView;
1363 return true;
1364 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08001365
Adam Powell696cba52011-03-29 10:38:16 -07001366 if (st.menu == null) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001367 return false;
1368 }
1369
Adam Powell696cba52011-03-29 10:38:16 -07001370 if (mPanelMenuPresenterCallback == null) {
1371 mPanelMenuPresenterCallback = new PanelMenuPresenterCallback();
1372 }
1373
Adam Powelldfee59a2011-08-05 20:48:30 -07001374 MenuView menuView = st.isInListMode()
Adam Powell538e5652011-10-11 13:47:08 -07001375 ? st.getListMenuView(getContext(), mPanelMenuPresenterCallback)
1376 : st.getIconMenuView(getContext(), mPanelMenuPresenterCallback);
Adam Powell696cba52011-03-29 10:38:16 -07001377
1378 st.shownPanelView = (View) menuView;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001379
1380 if (st.shownPanelView != null) {
1381 // Use the menu View's default animations if it has any
Adam Powell696cba52011-03-29 10:38:16 -07001382 final int defaultAnimations = menuView.getWindowAnimations();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001383 if (defaultAnimations != 0) {
1384 st.windowAnimations = defaultAnimations;
1385 }
1386 return true;
1387 } else {
1388 return false;
1389 }
1390 }
1391
1392 @Override
1393 public boolean performContextMenuIdentifierAction(int id, int flags) {
1394 return (mContextMenu != null) ? mContextMenu.performIdentifierAction(id, flags) : false;
1395 }
1396
1397 @Override
Alan Viverette79c067c52014-10-29 14:27:47 -07001398 public final void setElevation(float elevation) {
1399 mElevation = elevation;
1400 if (mDecor != null) {
1401 mDecor.setElevation(elevation);
1402 }
Alan Viverette71922de2015-01-12 16:14:02 -08001403 dispatchWindowAttributesChanged(getAttributes());
Alan Viverette79c067c52014-10-29 14:27:47 -07001404 }
1405
1406 @Override
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -07001407 public float getElevation() {
1408 return mElevation;
1409 }
1410
1411 @Override
Alan Viverette79c067c52014-10-29 14:27:47 -07001412 public final void setClipToOutline(boolean clipToOutline) {
1413 mClipToOutline = clipToOutline;
1414 if (mDecor != null) {
1415 mDecor.setClipToOutline(clipToOutline);
1416 }
1417 }
1418
1419 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001420 public final void setBackgroundDrawable(Drawable drawable) {
Dianne Hackborna7c176c2009-06-22 20:56:57 -07001421 if (drawable != mBackgroundDrawable || mBackgroundResource != 0) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001422 mBackgroundResource = 0;
1423 mBackgroundDrawable = drawable;
1424 if (mDecor != null) {
1425 mDecor.setWindowBackground(drawable);
1426 }
Adam Powellf849a5e2014-09-11 15:09:36 -07001427 if (mBackgroundFallbackResource != 0) {
1428 mDecor.setBackgroundFallback(drawable != null ? 0 : mBackgroundFallbackResource);
1429 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001430 }
1431 }
1432
1433 @Override
1434 public final void setFeatureDrawableResource(int featureId, int resId) {
1435 if (resId != 0) {
1436 DrawableFeatureState st = getDrawableState(featureId, true);
1437 if (st.resid != resId) {
1438 st.resid = resId;
1439 st.uri = null;
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001440 st.local = getContext().getDrawable(resId);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001441 updateDrawable(featureId, st, false);
1442 }
1443 } else {
1444 setFeatureDrawable(featureId, null);
1445 }
1446 }
1447
1448 @Override
1449 public final void setFeatureDrawableUri(int featureId, Uri uri) {
1450 if (uri != null) {
1451 DrawableFeatureState st = getDrawableState(featureId, true);
1452 if (st.uri == null || !st.uri.equals(uri)) {
1453 st.resid = 0;
1454 st.uri = uri;
1455 st.local = loadImageURI(uri);
1456 updateDrawable(featureId, st, false);
1457 }
1458 } else {
1459 setFeatureDrawable(featureId, null);
1460 }
1461 }
1462
1463 @Override
1464 public final void setFeatureDrawable(int featureId, Drawable drawable) {
1465 DrawableFeatureState st = getDrawableState(featureId, true);
1466 st.resid = 0;
1467 st.uri = null;
1468 if (st.local != drawable) {
1469 st.local = drawable;
1470 updateDrawable(featureId, st, false);
1471 }
1472 }
1473
1474 @Override
1475 public void setFeatureDrawableAlpha(int featureId, int alpha) {
1476 DrawableFeatureState st = getDrawableState(featureId, true);
1477 if (st.alpha != alpha) {
1478 st.alpha = alpha;
1479 updateDrawable(featureId, st, false);
1480 }
1481 }
1482
1483 protected final void setFeatureDefaultDrawable(int featureId, Drawable drawable) {
1484 DrawableFeatureState st = getDrawableState(featureId, true);
1485 if (st.def != drawable) {
1486 st.def = drawable;
1487 updateDrawable(featureId, st, false);
1488 }
1489 }
1490
1491 @Override
1492 public final void setFeatureInt(int featureId, int value) {
1493 // XXX Should do more management (as with drawable features) to
1494 // deal with interactions between multiple window policies.
1495 updateInt(featureId, value, false);
1496 }
1497
1498 /**
1499 * Update the state of a drawable feature. This should be called, for every
1500 * drawable feature supported, as part of onActive(), to make sure that the
1501 * contents of a containing window is properly updated.
1502 *
1503 * @see #onActive
1504 * @param featureId The desired drawable feature to change.
1505 * @param fromActive Always true when called from onActive().
1506 */
1507 protected final void updateDrawable(int featureId, boolean fromActive) {
1508 final DrawableFeatureState st = getDrawableState(featureId, false);
1509 if (st != null) {
1510 updateDrawable(featureId, st, fromActive);
1511 }
1512 }
1513
1514 /**
1515 * Called when a Drawable feature changes, for the window to update its
1516 * graphics.
1517 *
1518 * @param featureId The feature being changed.
1519 * @param drawable The new Drawable to show, or null if none.
1520 * @param alpha The new alpha blending of the Drawable.
1521 */
1522 protected void onDrawableChanged(int featureId, Drawable drawable, int alpha) {
1523 ImageView view;
1524 if (featureId == FEATURE_LEFT_ICON) {
1525 view = getLeftIconView();
1526 } else if (featureId == FEATURE_RIGHT_ICON) {
1527 view = getRightIconView();
1528 } else {
1529 return;
1530 }
1531
1532 if (drawable != null) {
1533 drawable.setAlpha(alpha);
1534 view.setImageDrawable(drawable);
1535 view.setVisibility(View.VISIBLE);
1536 } else {
1537 view.setVisibility(View.GONE);
1538 }
1539 }
1540
1541 /**
1542 * Called when an int feature changes, for the window to update its
1543 * graphics.
1544 *
1545 * @param featureId The feature being changed.
1546 * @param value The new integer value.
1547 */
1548 protected void onIntChanged(int featureId, int value) {
1549 if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) {
1550 updateProgressBars(value);
1551 } else if (featureId == FEATURE_CUSTOM_TITLE) {
Alan Viverette40982d42014-07-25 17:48:55 -07001552 FrameLayout titleContainer = (FrameLayout) findViewById(R.id.title_container);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001553 if (titleContainer != null) {
1554 mLayoutInflater.inflate(value, titleContainer);
1555 }
1556 }
1557 }
1558
1559 /**
1560 * Updates the progress bars that are shown in the title bar.
1561 *
1562 * @param value Can be one of {@link Window#PROGRESS_VISIBILITY_ON},
1563 * {@link Window#PROGRESS_VISIBILITY_OFF},
1564 * {@link Window#PROGRESS_INDETERMINATE_ON},
1565 * {@link Window#PROGRESS_INDETERMINATE_OFF}, or a value
1566 * starting at {@link Window#PROGRESS_START} through
1567 * {@link Window#PROGRESS_END} for setting the default
1568 * progress (if {@link Window#PROGRESS_END} is given,
1569 * the progress bar widgets in the title will be hidden after an
1570 * animation), a value between
1571 * {@link Window#PROGRESS_SECONDARY_START} -
1572 * {@link Window#PROGRESS_SECONDARY_END} for the
1573 * secondary progress (if
1574 * {@link Window#PROGRESS_SECONDARY_END} is given, the
1575 * progress bar widgets will still be shown with the secondary
1576 * progress bar will be completely filled in.)
1577 */
1578 private void updateProgressBars(int value) {
1579 ProgressBar circularProgressBar = getCircularProgressBar(true);
1580 ProgressBar horizontalProgressBar = getHorizontalProgressBar(true);
1581
1582 final int features = getLocalFeatures();
1583 if (value == PROGRESS_VISIBILITY_ON) {
1584 if ((features & (1 << FEATURE_PROGRESS)) != 0) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001585 if (horizontalProgressBar != null) {
1586 int level = horizontalProgressBar.getProgress();
1587 int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ?
1588 View.VISIBLE : View.INVISIBLE;
1589 horizontalProgressBar.setVisibility(visibility);
1590 } else {
1591 Log.e(TAG, "Horizontal progress bar not located in current window decor");
1592 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001593 }
1594 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001595 if (circularProgressBar != null) {
1596 circularProgressBar.setVisibility(View.VISIBLE);
1597 } else {
1598 Log.e(TAG, "Circular progress bar not located in current window decor");
1599 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001600 }
1601 } else if (value == PROGRESS_VISIBILITY_OFF) {
1602 if ((features & (1 << FEATURE_PROGRESS)) != 0) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001603 if (horizontalProgressBar != null) {
1604 horizontalProgressBar.setVisibility(View.GONE);
1605 } else {
1606 Log.e(TAG, "Horizontal progress bar not located in current window decor");
1607 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001608 }
1609 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001610 if (circularProgressBar != null) {
1611 circularProgressBar.setVisibility(View.GONE);
1612 } else {
1613 Log.e(TAG, "Circular progress bar not located in current window decor");
1614 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001615 }
1616 } else if (value == PROGRESS_INDETERMINATE_ON) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001617 if (horizontalProgressBar != null) {
1618 horizontalProgressBar.setIndeterminate(true);
1619 } else {
1620 Log.e(TAG, "Horizontal progress bar not located in current window decor");
1621 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001622 } else if (value == PROGRESS_INDETERMINATE_OFF) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001623 if (horizontalProgressBar != null) {
1624 horizontalProgressBar.setIndeterminate(false);
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 (PROGRESS_START <= value && value <= PROGRESS_END) {
1629 // We want to set the progress value before testing for visibility
1630 // so that when the progress bar becomes visible again, it has the
1631 // correct level.
Adam Powelleec8f0c2014-05-30 11:00:00 -07001632 if (horizontalProgressBar != null) {
1633 horizontalProgressBar.setProgress(value - PROGRESS_START);
1634 } else {
1635 Log.e(TAG, "Horizontal progress bar not located in current window decor");
1636 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001637
1638 if (value < PROGRESS_END) {
1639 showProgressBars(horizontalProgressBar, circularProgressBar);
1640 } else {
1641 hideProgressBars(horizontalProgressBar, circularProgressBar);
1642 }
1643 } else if (PROGRESS_SECONDARY_START <= value && value <= PROGRESS_SECONDARY_END) {
Adam Powelleec8f0c2014-05-30 11:00:00 -07001644 if (horizontalProgressBar != null) {
1645 horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START);
1646 } else {
1647 Log.e(TAG, "Horizontal progress bar not located in current window decor");
1648 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001649
1650 showProgressBars(horizontalProgressBar, circularProgressBar);
1651 }
1652
1653 }
1654
1655 private void showProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
1656 final int features = getLocalFeatures();
1657 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
Adam Powelleec8f0c2014-05-30 11:00:00 -07001658 spinnyProgressBar != null && spinnyProgressBar.getVisibility() == View.INVISIBLE) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001659 spinnyProgressBar.setVisibility(View.VISIBLE);
1660 }
1661 // Only show the progress bars if the primary progress is not complete
Adam Powelleec8f0c2014-05-30 11:00:00 -07001662 if ((features & (1 << FEATURE_PROGRESS)) != 0 && horizontalProgressBar != null &&
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001663 horizontalProgressBar.getProgress() < 10000) {
1664 horizontalProgressBar.setVisibility(View.VISIBLE);
1665 }
1666 }
1667
1668 private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
1669 final int features = getLocalFeatures();
Alan Viverette40982d42014-07-25 17:48:55 -07001670 Animation anim = AnimationUtils.loadAnimation(getContext(), R.anim.fade_out);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001671 anim.setDuration(1000);
1672 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
Adam Powelleec8f0c2014-05-30 11:00:00 -07001673 spinnyProgressBar != null &&
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001674 spinnyProgressBar.getVisibility() == View.VISIBLE) {
1675 spinnyProgressBar.startAnimation(anim);
1676 spinnyProgressBar.setVisibility(View.INVISIBLE);
1677 }
Adam Powelleec8f0c2014-05-30 11:00:00 -07001678 if ((features & (1 << FEATURE_PROGRESS)) != 0 && horizontalProgressBar != null &&
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001679 horizontalProgressBar.getVisibility() == View.VISIBLE) {
1680 horizontalProgressBar.startAnimation(anim);
1681 horizontalProgressBar.setVisibility(View.INVISIBLE);
1682 }
1683 }
1684
Adam Powell04fe6eb2013-05-31 14:39:48 -07001685 @Override
1686 public void setIcon(int resId) {
1687 mIconRes = resId;
1688 mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON;
Adam Powell0a317e92013-06-13 13:15:43 -07001689 mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
Adam Powell4369e7d2014-05-17 14:16:08 -07001690 if (mDecorContentParent != null) {
1691 mDecorContentParent.setIcon(resId);
Adam Powell04fe6eb2013-05-31 14:39:48 -07001692 }
1693 }
1694
1695 @Override
1696 public void setDefaultIcon(int resId) {
1697 if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0) {
1698 return;
1699 }
1700 mIconRes = resId;
Adam Powell4369e7d2014-05-17 14:16:08 -07001701 if (mDecorContentParent != null && (!mDecorContentParent.hasIcon() ||
Adam Powell0a317e92013-06-13 13:15:43 -07001702 (mResourcesSetFlags & FLAG_RESOURCE_SET_ICON_FALLBACK) != 0)) {
1703 if (resId != 0) {
Adam Powell4369e7d2014-05-17 14:16:08 -07001704 mDecorContentParent.setIcon(resId);
Adam Powell0a317e92013-06-13 13:15:43 -07001705 mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
1706 } else {
Adam Powell4369e7d2014-05-17 14:16:08 -07001707 mDecorContentParent.setIcon(
1708 getContext().getPackageManager().getDefaultActivityIcon());
Adam Powell0a317e92013-06-13 13:15:43 -07001709 mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
1710 }
Adam Powell04fe6eb2013-05-31 14:39:48 -07001711 }
1712 }
1713
1714 @Override
1715 public void setLogo(int resId) {
1716 mLogoRes = resId;
1717 mResourcesSetFlags |= FLAG_RESOURCE_SET_LOGO;
Adam Powell4369e7d2014-05-17 14:16:08 -07001718 if (mDecorContentParent != null) {
1719 mDecorContentParent.setLogo(resId);
Adam Powell04fe6eb2013-05-31 14:39:48 -07001720 }
1721 }
1722
1723 @Override
1724 public void setDefaultLogo(int resId) {
1725 if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0) {
1726 return;
1727 }
1728 mLogoRes = resId;
Adam Powell4369e7d2014-05-17 14:16:08 -07001729 if (mDecorContentParent != null && !mDecorContentParent.hasLogo()) {
1730 mDecorContentParent.setLogo(resId);
Adam Powell04fe6eb2013-05-31 14:39:48 -07001731 }
1732 }
1733
keunyoung30f420f2013-08-02 14:23:10 -07001734 @Override
1735 public void setLocalFocus(boolean hasFocus, boolean inTouchMode) {
1736 getViewRootImpl().windowFocusChanged(hasFocus, inTouchMode);
1737
1738 }
1739
1740 @Override
1741 public void injectInputEvent(InputEvent event) {
1742 getViewRootImpl().dispatchInputEvent(event);
1743 }
1744
1745 private ViewRootImpl getViewRootImpl() {
1746 if (mDecor != null) {
1747 ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
1748 if (viewRootImpl != null) {
1749 return viewRootImpl;
1750 }
1751 }
1752 throw new IllegalStateException("view not added");
1753 }
1754
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001755 /**
1756 * Request that key events come to this activity. Use this if your activity
1757 * has no views with focus, but the activity still wants a chance to process
1758 * key events.
1759 */
1760 @Override
1761 public void takeKeyEvents(boolean get) {
1762 mDecor.setFocusable(get);
1763 }
1764
1765 @Override
1766 public boolean superDispatchKeyEvent(KeyEvent event) {
1767 return mDecor.superDispatchKeyEvent(event);
1768 }
1769
1770 @Override
Jeff Brown64da12a2011-01-04 19:57:47 -08001771 public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
1772 return mDecor.superDispatchKeyShortcutEvent(event);
1773 }
1774
1775 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001776 public boolean superDispatchTouchEvent(MotionEvent event) {
1777 return mDecor.superDispatchTouchEvent(event);
1778 }
1779
1780 @Override
1781 public boolean superDispatchTrackballEvent(MotionEvent event) {
1782 return mDecor.superDispatchTrackballEvent(event);
1783 }
1784
Jeff Browncb1404e2011-01-15 18:14:15 -08001785 @Override
1786 public boolean superDispatchGenericMotionEvent(MotionEvent event) {
1787 return mDecor.superDispatchGenericMotionEvent(event);
1788 }
1789
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001790 /**
1791 * A key was pressed down and not handled by anything else in the window.
1792 *
1793 * @see #onKeyUp
1794 * @see android.view.KeyEvent
1795 */
1796 protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
Joe Onorato86f67862010-11-05 18:57:34 -07001797 /* ****************************************************************************
1798 * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
1799 *
1800 * If your key handling must happen before the app gets a crack at the event,
1801 * it goes in PhoneWindowManager.
1802 *
1803 * If your key handling should happen in all windows, and does not depend on
1804 * the state of the current application, other than that the current
1805 * application can override the behavior by handling the event itself, it
1806 * should go in PhoneFallbackEventHandler.
1807 *
1808 * Only if your handling depends on the window, and the fact that it has
1809 * a DecorView, should it go here.
1810 * ****************************************************************************/
1811
Dianne Hackborna207baa2009-09-13 16:14:44 -07001812 final KeyEvent.DispatcherState dispatcher =
1813 mDecor != null ? mDecor.getKeyDispatcherState() : null;
1814 //Log.i(TAG, "Key down: repeat=" + event.getRepeatCount()
1815 // + " flags=0x" + Integer.toHexString(event.getFlags()));
Alan Viveretteeb1d3792014-06-03 18:36:03 -07001816
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001817 switch (keyCode) {
1818 case KeyEvent.KEYCODE_VOLUME_UP:
RoboErik5452e252015-02-06 15:33:53 -08001819 case KeyEvent.KEYCODE_VOLUME_DOWN:
1820 case KeyEvent.KEYCODE_VOLUME_MUTE: {
1821 int direction = 0;
1822 switch (keyCode) {
1823 case KeyEvent.KEYCODE_VOLUME_UP:
1824 direction = AudioManager.ADJUST_RAISE;
1825 break;
1826 case KeyEvent.KEYCODE_VOLUME_DOWN:
1827 direction = AudioManager.ADJUST_LOWER;
1828 break;
1829 case KeyEvent.KEYCODE_VOLUME_MUTE:
1830 direction = AudioManager.ADJUST_TOGGLE_MUTE;
1831 break;
1832 }
RoboErik55011652014-07-09 15:05:53 -07001833 // If we have a session send it the volume command, otherwise
1834 // use the suggested stream.
1835 if (mMediaController != null) {
RoboErik1ff5b162014-07-15 17:23:18 -07001836 mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);
RoboErik55011652014-07-09 15:05:53 -07001837 } else {
1838 MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
John Spurlock0635b892014-07-19 17:52:35 -04001839 mVolumeControlStreamType, direction,
John Spurlockb94f2d62015-03-17 14:11:57 -04001840 AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE
1841 | AudioManager.FLAG_FROM_KEY);
RoboErik55011652014-07-09 15:05:53 -07001842 }
1843 return true;
1844 }
RoboErik55011652014-07-09 15:05:53 -07001845 // These are all the recognized media key codes in
1846 // KeyEvent.isMediaKey()
1847 case KeyEvent.KEYCODE_MEDIA_PLAY:
1848 case KeyEvent.KEYCODE_MEDIA_PAUSE:
1849 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
1850 case KeyEvent.KEYCODE_MUTE:
1851 case KeyEvent.KEYCODE_HEADSETHOOK:
1852 case KeyEvent.KEYCODE_MEDIA_STOP:
1853 case KeyEvent.KEYCODE_MEDIA_NEXT:
1854 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
1855 case KeyEvent.KEYCODE_MEDIA_REWIND:
1856 case KeyEvent.KEYCODE_MEDIA_RECORD:
1857 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
1858 if (mMediaController != null) {
1859 if (mMediaController.dispatchMediaButtonEvent(event)) {
1860 return true;
1861 }
1862 }
RoboErik28204a72014-07-17 12:17:27 -07001863 return false;
RoboErik55011652014-07-09 15:05:53 -07001864 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001865
1866 case KeyEvent.KEYCODE_MENU: {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001867 onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
1868 return true;
1869 }
1870
1871 case KeyEvent.KEYCODE_BACK: {
1872 if (event.getRepeatCount() > 0) break;
1873 if (featureId < 0) break;
Dianne Hackbornfed9cb52009-09-14 21:23:11 -07001874 // Currently don't do anything with long press.
Winson Chung45d378b2011-09-08 19:02:06 -07001875 if (dispatcher != null) {
1876 dispatcher.startTracking(event, this);
1877 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001878 return true;
1879 }
1880
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001881 }
1882
1883 return false;
1884 }
1885
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001886 private KeyguardManager getKeyguardManager() {
1887 if (mKeyguardManager == null) {
Joe Onorato86f67862010-11-05 18:57:34 -07001888 mKeyguardManager = (KeyguardManager) getContext().getSystemService(
1889 Context.KEYGUARD_SERVICE);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001890 }
1891 return mKeyguardManager;
1892 }
Joe Onorato86f67862010-11-05 18:57:34 -07001893
1894 AudioManager getAudioManager() {
1895 if (mAudioManager == null) {
1896 mAudioManager = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
Mike LeBeaubfd25ca2010-03-22 17:40:35 -07001897 }
Joe Onorato86f67862010-11-05 18:57:34 -07001898 return mAudioManager;
Mike LeBeaubfd25ca2010-03-22 17:40:35 -07001899 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001900
1901 /**
1902 * A key was released and not handled by anything else in the window.
1903 *
1904 * @see #onKeyDown
1905 * @see android.view.KeyEvent
1906 */
1907 protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) {
Dianne Hackborna207baa2009-09-13 16:14:44 -07001908 final KeyEvent.DispatcherState dispatcher =
1909 mDecor != null ? mDecor.getKeyDispatcherState() : null;
1910 if (dispatcher != null) {
1911 dispatcher.handleUpEvent(event);
1912 }
1913 //Log.i(TAG, "Key up: repeat=" + event.getRepeatCount()
1914 // + " flags=0x" + Integer.toHexString(event.getFlags()));
Alan Viveretteeb1d3792014-06-03 18:36:03 -07001915
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001916 switch (keyCode) {
1917 case KeyEvent.KEYCODE_VOLUME_UP:
RoboErik55011652014-07-09 15:05:53 -07001918 case KeyEvent.KEYCODE_VOLUME_DOWN: {
John Spurlockb94f2d62015-03-17 14:11:57 -04001919 final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
1920 | AudioManager.FLAG_FROM_KEY;
RoboErik55011652014-07-09 15:05:53 -07001921 // If we have a session send it the volume command, otherwise
1922 // use the suggested stream.
1923 if (mMediaController != null) {
John Spurlockb94f2d62015-03-17 14:11:57 -04001924 mMediaController.adjustVolume(0, flags);
RoboErik55011652014-07-09 15:05:53 -07001925 } else {
1926 MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
John Spurlockb94f2d62015-03-17 14:11:57 -04001927 mVolumeControlStreamType, 0, flags);
RoboErik55011652014-07-09 15:05:53 -07001928 }
1929 return true;
1930 }
Jeff Brownb0418da2010-11-01 15:24:01 -07001931 case KeyEvent.KEYCODE_VOLUME_MUTE: {
Joe Onorato86f67862010-11-05 18:57:34 -07001932 // Similar code is in PhoneFallbackEventHandler in case the window
1933 // doesn't have one of these. In this case, we execute it here and
1934 // eat the event instead, because we have mVolumeControlStreamType
1935 // and they don't.
Mike Lockwoodce952c82011-11-14 10:47:42 -08001936 getAudioManager().handleKeyUp(event, mVolumeControlStreamType);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001937 return true;
1938 }
RoboErik55011652014-07-09 15:05:53 -07001939 // These are all the recognized media key codes in
1940 // KeyEvent.isMediaKey()
1941 case KeyEvent.KEYCODE_MEDIA_PLAY:
1942 case KeyEvent.KEYCODE_MEDIA_PAUSE:
1943 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
1944 case KeyEvent.KEYCODE_MUTE:
1945 case KeyEvent.KEYCODE_HEADSETHOOK:
1946 case KeyEvent.KEYCODE_MEDIA_STOP:
1947 case KeyEvent.KEYCODE_MEDIA_NEXT:
1948 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
1949 case KeyEvent.KEYCODE_MEDIA_REWIND:
1950 case KeyEvent.KEYCODE_MEDIA_RECORD:
1951 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
1952 if (mMediaController != null) {
1953 if (mMediaController.dispatchMediaButtonEvent(event)) {
1954 return true;
1955 }
1956 }
RoboErik28204a72014-07-17 12:17:27 -07001957 return false;
RoboErik55011652014-07-09 15:05:53 -07001958 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001959
1960 case KeyEvent.KEYCODE_MENU: {
Adam Powellf6148c52010-08-11 21:10:16 -07001961 onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId,
1962 event);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001963 return true;
1964 }
1965
Dianne Hackborna207baa2009-09-13 16:14:44 -07001966 case KeyEvent.KEYCODE_BACK: {
1967 if (featureId < 0) break;
Dianne Hackbornfed9cb52009-09-14 21:23:11 -07001968 if (event.isTracking() && !event.isCanceled()) {
1969 if (featureId == FEATURE_OPTIONS_PANEL) {
1970 PanelFeatureState st = getPanelState(featureId, false);
1971 if (st != null && st.isInExpandedMode) {
1972 // If the user is in an expanded menu and hits back, it
1973 // should go back to the icon menu
1974 reopenMenu(true);
1975 return true;
1976 }
Dianne Hackborna207baa2009-09-13 16:14:44 -07001977 }
Dianne Hackbornfed9cb52009-09-14 21:23:11 -07001978 closePanel(featureId);
1979 return true;
Dianne Hackborna207baa2009-09-13 16:14:44 -07001980 }
Dianne Hackbornfed9cb52009-09-14 21:23:11 -07001981 break;
Dianne Hackborna207baa2009-09-13 16:14:44 -07001982 }
1983
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001984 case KeyEvent.KEYCODE_SEARCH: {
1985 /*
1986 * Do this in onKeyUp since the Search key is also used for
1987 * chording quick launch shortcuts.
1988 */
Dianne Hackborna207baa2009-09-13 16:14:44 -07001989 if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001990 break;
1991 }
Dianne Hackborna207baa2009-09-13 16:14:44 -07001992 if (event.isTracking() && !event.isCanceled()) {
Tim Kilbourn6a975b32015-04-09 17:14:34 -07001993 launchDefaultSearch(event);
Dianne Hackborn0041e972009-07-24 17:14:43 -07001994 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001995 return true;
1996 }
1997 }
1998
1999 return false;
2000 }
2001
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002002 @Override
2003 protected void onActive() {
2004 }
2005
2006 @Override
2007 public final View getDecorView() {
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -07002008 if (mDecor == null || mForceDecorInstall) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002009 installDecor();
2010 }
2011 return mDecor;
2012 }
2013
2014 @Override
2015 public final View peekDecorView() {
2016 return mDecor;
2017 }
2018
2019 static private final String FOCUSED_ID_TAG = "android:focusedViewId";
Alan Viveretteec6cf182015-08-13 15:31:57 -04002020 static private final String ACCESSIBILITY_FOCUSED_ID_TAG = "android:accessibilityFocusedViewId";
2021 static private final String ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG =
2022 "android:accessibilityFocusedVirtualViewId";
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002023 static private final String VIEWS_TAG = "android:views";
2024 static private final String PANELS_TAG = "android:Panels";
Adam Powell6c6f5752010-08-20 18:34:46 -07002025 static private final String ACTION_BAR_TAG = "android:ActionBar";
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002026
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002027 /** {@inheritDoc} */
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002028 @Override
2029 public Bundle saveHierarchyState() {
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002030 Bundle outState = new Bundle();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002031 if (mContentParent == null) {
2032 return outState;
2033 }
2034
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002035 SparseArray<Parcelable> states = new SparseArray<Parcelable>();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002036 mContentParent.saveHierarchyState(states);
2037 outState.putSparseParcelableArray(VIEWS_TAG, states);
2038
Alan Viveretteec6cf182015-08-13 15:31:57 -04002039 // Save the focused view ID.
2040 final View focusedView = mContentParent.findFocus();
2041 if (focusedView != null && focusedView.getId() != View.NO_ID) {
2042 outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
2043 }
2044
2045 // Save the accessibility focused view ID.
Alan Viverette4cbd3ac2015-08-19 10:07:29 -04002046 if (mDecor != null) {
2047 final ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
2048 if (viewRootImpl != null) {
2049 final View accessFocusHost = viewRootImpl.getAccessibilityFocusedHost();
2050 if (accessFocusHost != null && accessFocusHost.getId() != View.NO_ID) {
2051 outState.putInt(ACCESSIBILITY_FOCUSED_ID_TAG, accessFocusHost.getId());
Alan Viveretteec6cf182015-08-13 15:31:57 -04002052
Alan Viverette4cbd3ac2015-08-19 10:07:29 -04002053 // If we have a focused virtual node ID, save that too.
2054 final AccessibilityNodeInfo accessFocusedNode =
2055 viewRootImpl.getAccessibilityFocusedVirtualView();
2056 if (accessFocusedNode != null) {
2057 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2058 accessFocusedNode.getSourceNodeId());
2059 outState.putInt(ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG, virtualNodeId);
2060 }
2061 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002062 }
2063 }
2064
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002065 // save the panels
2066 SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002067 savePanelState(panelStates);
2068 if (panelStates.size() > 0) {
2069 outState.putSparseParcelableArray(PANELS_TAG, panelStates);
2070 }
2071
Adam Powell4369e7d2014-05-17 14:16:08 -07002072 if (mDecorContentParent != null) {
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002073 SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>();
Adam Powell4369e7d2014-05-17 14:16:08 -07002074 mDecorContentParent.saveToolbarHierarchyState(actionBarStates);
Adam Powell8d02dea2011-05-31 21:35:13 -07002075 outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);
Adam Powell6c6f5752010-08-20 18:34:46 -07002076 }
2077
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002078 return outState;
2079 }
2080
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002081 /** {@inheritDoc} */
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002082 @Override
2083 public void restoreHierarchyState(Bundle savedInstanceState) {
2084 if (mContentParent == null) {
2085 return;
2086 }
2087
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002088 SparseArray<Parcelable> savedStates
2089 = savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002090 if (savedStates != null) {
2091 mContentParent.restoreHierarchyState(savedStates);
2092 }
2093
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002094 // restore the focused view
2095 int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002096 if (focusedViewId != View.NO_ID) {
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002097 View needsFocus = mContentParent.findViewById(focusedViewId);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002098 if (needsFocus != null) {
2099 needsFocus.requestFocus();
2100 } else {
Alan Viveretteeae66cd2015-08-13 20:05:35 +00002101 Log.w(TAG,
2102 "Previously focused view reported id " + focusedViewId
2103 + " during save, but can't be found during restore.");
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002104 }
2105 }
2106
Alan Viveretteec6cf182015-08-13 15:31:57 -04002107 // Restore the accessibility focused view.
2108 final int accessFocusHostViewId = savedInstanceState.getInt(
2109 ACCESSIBILITY_FOCUSED_ID_TAG, View.NO_ID);
2110 final int accessFocusVirtualViewId = savedInstanceState.getInt(
2111 ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG, AccessibilityNodeInfo.UNDEFINED_ITEM_ID);
2112 tryRestoreAccessibilityFocus(accessFocusHostViewId, accessFocusVirtualViewId);
2113
2114 // Restore the panels.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002115 SparseArray<Parcelable> panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);
2116 if (panelStates != null) {
2117 restorePanelState(panelStates);
2118 }
Adam Powell6c6f5752010-08-20 18:34:46 -07002119
Adam Powell4369e7d2014-05-17 14:16:08 -07002120 if (mDecorContentParent != null) {
Adam Powell8d02dea2011-05-31 21:35:13 -07002121 SparseArray<Parcelable> actionBarStates =
2122 savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG);
Adam Powellfb5f1bc2012-05-17 19:30:35 -07002123 if (actionBarStates != null) {
Adam Powell31c91c82014-08-22 17:20:00 -07002124 doPendingInvalidatePanelMenu();
Adam Powell4369e7d2014-05-17 14:16:08 -07002125 mDecorContentParent.restoreToolbarHierarchyState(actionBarStates);
Adam Powellfb5f1bc2012-05-17 19:30:35 -07002126 } else {
2127 Log.w(TAG, "Missing saved instance states for action bar views! " +
2128 "State will not be restored.");
2129 }
Adam Powell6c6f5752010-08-20 18:34:46 -07002130 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002131 }
2132
Alan Viveretteec6cf182015-08-13 15:31:57 -04002133 private void tryRestoreAccessibilityFocus(int hostViewId, int virtualViewId) {
Alan Viverette4cbd3ac2015-08-19 10:07:29 -04002134 if (hostViewId != View.NO_ID && mDecor != null) {
2135 final View needsAccessFocus = mDecor.findViewById(hostViewId);
Alan Viveretteec6cf182015-08-13 15:31:57 -04002136 if (needsAccessFocus != null) {
2137 if (!tryFocusingVirtualView(needsAccessFocus, virtualViewId)
2138 && !needsAccessFocus.requestAccessibilityFocus()) {
2139 Log.w(TAG, "Failed to restore focus to previously accessibility"
2140 + " focused view with id " + hostViewId);
2141 }
2142 } else {
2143 Log.w(TAG, "Previously accessibility focused view reported id " + hostViewId
2144 + " during save, but can't be found during restore.");
2145 }
2146 }
2147 }
2148
2149 private boolean tryFocusingVirtualView(View host, int virtualViewId) {
2150 if (virtualViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
2151 final AccessibilityNodeProvider nodeProvider = host.getAccessibilityNodeProvider();
2152 if (nodeProvider != null) {
2153 return nodeProvider.performAction(virtualViewId,
2154 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
2155 }
2156 }
2157 return false;
2158 }
2159
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002160 /**
2161 * Invoked when the panels should freeze their state.
2162 *
2163 * @param icicles Save state into this. This is usually indexed by the
2164 * featureId. This will be given to {@link #restorePanelState} in the
2165 * future.
2166 */
2167 private void savePanelState(SparseArray<Parcelable> icicles) {
2168 PanelFeatureState[] panels = mPanels;
2169 if (panels == null) {
2170 return;
2171 }
2172
2173 for (int curFeatureId = panels.length - 1; curFeatureId >= 0; curFeatureId--) {
2174 if (panels[curFeatureId] != null) {
2175 icicles.put(curFeatureId, panels[curFeatureId].onSaveInstanceState());
2176 }
2177 }
2178 }
2179
2180 /**
2181 * Invoked when the panels should thaw their state from a previously frozen state.
2182 *
2183 * @param icicles The state saved by {@link #savePanelState} that needs to be thawed.
2184 */
2185 private void restorePanelState(SparseArray<Parcelable> icicles) {
2186 PanelFeatureState st;
Dmitry Tsyganyuk554bb012012-04-02 13:10:52 -05002187 int curFeatureId;
2188 for (int i = icicles.size() - 1; i >= 0; i--) {
2189 curFeatureId = icicles.keyAt(i);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002190 st = getPanelState(curFeatureId, false /* required */);
2191 if (st == null) {
2192 // The panel must not have been required, and is currently not around, skip it
2193 continue;
2194 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002195
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002196 st.onRestoreInstanceState(icicles.get(curFeatureId));
Adam Powell31bb97d2011-05-03 20:58:31 -07002197 invalidatePanelMenu(curFeatureId);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002198 }
2199
2200 /*
2201 * Implementation note: call openPanelsAfterRestore later to actually open the
2202 * restored panels.
2203 */
2204 }
2205
2206 /**
2207 * Opens the panels that have had their state restored. This should be
2208 * called sometime after {@link #restorePanelState} when it is safe to add
2209 * to the window manager.
2210 */
Wale Ogunwale8804af22015-11-17 09:18:15 -08002211 void openPanelsAfterRestore() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002212 PanelFeatureState[] panels = mPanels;
2213
2214 if (panels == null) {
2215 return;
2216 }
2217
2218 PanelFeatureState st;
2219 for (int i = panels.length - 1; i >= 0; i--) {
2220 st = panels[i];
Dianne Hackbornd0071442009-09-25 01:35:29 -07002221 // We restore the panel if it was last open; we skip it if it
2222 // now is open, to avoid a race condition if the user immediately
2223 // opens it when we are resuming.
Adam Powell11ed1d62011-07-11 21:19:59 -07002224 if (st != null) {
2225 st.applyFrozenState();
2226 if (!st.isOpen && st.wasLastOpen) {
2227 st.isInExpandedMode = st.wasLastExpanded;
2228 openPanel(st, null);
2229 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002230 }
2231 }
2232 }
2233
Adam Powell696cba52011-03-29 10:38:16 -07002234 private class PanelMenuPresenterCallback implements MenuPresenter.Callback {
2235 @Override
2236 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
2237 final Menu parentMenu = menu.getRootMenu();
2238 final boolean isSubMenu = parentMenu != menu;
2239 final PanelFeatureState panel = findMenuPanel(isSubMenu ? parentMenu : menu);
2240 if (panel != null) {
2241 if (isSubMenu) {
2242 callOnPanelClosed(panel.featureId, panel, parentMenu);
2243 closePanel(panel, true);
2244 } else {
2245 // Close the panel and only do the callback if the menu is being
2246 // closed completely, not if opening a sub menu
2247 closePanel(panel, allMenusAreClosing);
2248 }
2249 }
2250 }
2251
2252 @Override
2253 public boolean onOpenSubMenu(MenuBuilder subMenu) {
2254 if (subMenu == null && hasFeature(FEATURE_ACTION_BAR)) {
2255 Callback cb = getCallback();
2256 if (cb != null && !isDestroyed()) {
2257 cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
2258 }
2259 }
2260
2261 return true;
2262 }
2263 }
2264
2265 private final class ActionMenuPresenterCallback implements MenuPresenter.Callback {
2266 @Override
2267 public boolean onOpenSubMenu(MenuBuilder subMenu) {
2268 Callback cb = getCallback();
2269 if (cb != null) {
2270 cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
2271 return true;
2272 }
2273 return false;
2274 }
2275
2276 @Override
2277 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
2278 checkCloseActionMenu(menu);
2279 }
2280 }
2281
Stefan Kuhne61b47bb2015-07-28 14:04:25 -07002282 protected DecorView generateDecor(int featureId) {
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07002283 // System process doesn't have application context and in that case we need to directly use
2284 // the context we have. Otherwise we want the application context, so we don't cling to the
2285 // activity.
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07002286 Context context;
Filip Gruszczynski796b8c12015-12-22 14:46:21 -08002287 if (mUseDecorContext) {
2288 Context applicationContext = getContext().getApplicationContext();
2289 if (applicationContext == null) {
2290 context = getContext();
2291 } else {
2292 context = new DecorContext(applicationContext);
2293 if (mTheme != -1) {
2294 context.setTheme(mTheme);
2295 }
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07002296 }
Filip Gruszczynski796b8c12015-12-22 14:46:21 -08002297 } else {
2298 context = getContext();
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07002299 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002300 return new DecorView(context, featureId, this, getAttributes());
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002301 }
2302
2303 protected ViewGroup generateLayout(DecorView decor) {
2304 // Apply data from current theme.
2305
2306 TypedArray a = getWindowStyle();
2307
2308 if (false) {
2309 System.out.println("From style:");
2310 String s = "Attrs:";
Alan Viverette40982d42014-07-25 17:48:55 -07002311 for (int i = 0; i < R.styleable.Window.length; i++) {
2312 s = s + " " + Integer.toHexString(R.styleable.Window[i]) + "="
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002313 + a.getString(i);
2314 }
2315 System.out.println(s);
2316 }
2317
Alan Viverette40982d42014-07-25 17:48:55 -07002318 mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002319 int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
2320 & (~getForcedWindowFlags());
2321 if (mIsFloating) {
2322 setLayout(WRAP_CONTENT, WRAP_CONTENT);
2323 setFlags(0, flagsToUpdate);
2324 } else {
2325 setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
2326 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002327
Alan Viverette40982d42014-07-25 17:48:55 -07002328 if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002329 requestFeature(FEATURE_NO_TITLE);
Alan Viverette40982d42014-07-25 17:48:55 -07002330 } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
Adam Powell33b97432010-04-20 10:01:14 -07002331 // Don't allow an action bar if there is no title.
2332 requestFeature(FEATURE_ACTION_BAR);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002333 }
2334
Alan Viverette40982d42014-07-25 17:48:55 -07002335 if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {
Adam Powell6b336f82010-08-10 20:13:01 -07002336 requestFeature(FEATURE_ACTION_BAR_OVERLAY);
2337 }
2338
Alan Viverette40982d42014-07-25 17:48:55 -07002339 if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {
Adam Powell5d279772010-07-27 16:34:07 -07002340 requestFeature(FEATURE_ACTION_MODE_OVERLAY);
2341 }
2342
Alan Viverette40982d42014-07-25 17:48:55 -07002343 if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {
Will Haldean Brownca6234e2014-02-12 10:23:41 -08002344 requestFeature(FEATURE_SWIPE_TO_DISMISS);
2345 }
2346
Alan Viverette40982d42014-07-25 17:48:55 -07002347 if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
Dianne Hackbornc652de82013-02-15 16:32:56 -08002348 setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
2349 }
2350
Alan Viverette40982d42014-07-25 17:48:55 -07002351 if (a.getBoolean(R.styleable.Window_windowTranslucentStatus,
John Spurlockbd957402013-10-03 11:38:39 -04002352 false)) {
2353 setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS
2354 & (~getForcedWindowFlags()));
2355 }
2356
Alan Viverette40982d42014-07-25 17:48:55 -07002357 if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation,
John Spurlockbd957402013-10-03 11:38:39 -04002358 false)) {
2359 setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION
2360 & (~getForcedWindowFlags()));
2361 }
2362
Alan Viverette40982d42014-07-25 17:48:55 -07002363 if (a.getBoolean(R.styleable.Window_windowOverscan, false)) {
Dianne Hackbornc652de82013-02-15 16:32:56 -08002364 setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002365 }
2366
Alan Viverette40982d42014-07-25 17:48:55 -07002367 if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
Dianne Hackborn4bf7bcf2009-08-09 17:23:00 -07002368 setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
2369 }
2370
Alan Viverette40982d42014-07-25 17:48:55 -07002371 if (a.getBoolean(R.styleable.Window_windowEnableSplitTouch,
Jeff Brown46e75292010-11-10 16:53:45 -08002372 getContext().getApplicationInfo().targetSdkVersion
2373 >= android.os.Build.VERSION_CODES.HONEYCOMB)) {
2374 setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags()));
2375 }
2376
Alan Viverette40982d42014-07-25 17:48:55 -07002377 a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
2378 a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002379 if (DEBUG) Log.d(TAG, "Min width minor: " + mMinWidthMinor.coerceToString()
2380 + ", major: " + mMinWidthMajor.coerceToString());
Alan Viverette40982d42014-07-25 17:48:55 -07002381 if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {
Adam Powell40eec4c2012-02-15 17:10:58 -08002382 if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
Alan Viverette40982d42014-07-25 17:48:55 -07002383 a.getValue(R.styleable.Window_windowFixedWidthMajor,
Adam Powell40eec4c2012-02-15 17:10:58 -08002384 mFixedWidthMajor);
2385 }
Alan Viverette40982d42014-07-25 17:48:55 -07002386 if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) {
Adam Powell40eec4c2012-02-15 17:10:58 -08002387 if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue();
Alan Viverette40982d42014-07-25 17:48:55 -07002388 a.getValue(R.styleable.Window_windowFixedWidthMinor,
Adam Powell40eec4c2012-02-15 17:10:58 -08002389 mFixedWidthMinor);
2390 }
Alan Viverette40982d42014-07-25 17:48:55 -07002391 if (a.hasValue(R.styleable.Window_windowFixedHeightMajor)) {
Adam Powell40eec4c2012-02-15 17:10:58 -08002392 if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue();
Alan Viverette40982d42014-07-25 17:48:55 -07002393 a.getValue(R.styleable.Window_windowFixedHeightMajor,
Adam Powell40eec4c2012-02-15 17:10:58 -08002394 mFixedHeightMajor);
2395 }
Alan Viverette40982d42014-07-25 17:48:55 -07002396 if (a.hasValue(R.styleable.Window_windowFixedHeightMinor)) {
Adam Powell40eec4c2012-02-15 17:10:58 -08002397 if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
Alan Viverette40982d42014-07-25 17:48:55 -07002398 a.getValue(R.styleable.Window_windowFixedHeightMinor,
Adam Powell40eec4c2012-02-15 17:10:58 -08002399 mFixedHeightMinor);
2400 }
Alan Viverette40982d42014-07-25 17:48:55 -07002401 if (a.getBoolean(R.styleable.Window_windowContentTransitions, false)) {
Adam Powell18e905f2013-10-24 14:27:48 -07002402 requestFeature(FEATURE_CONTENT_TRANSITIONS);
Michael Kolb4bb047f2014-04-01 14:38:57 -07002403 }
George Mount9826f632014-09-11 08:50:09 -07002404 if (a.getBoolean(R.styleable.Window_windowActivityTransitions, false)) {
2405 requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
2406 }
Filip Gruszczynskib57503c2014-07-16 16:35:18 -07002407
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002408 mIsTranslucent = a.getBoolean(R.styleable.Window_windowIsTranslucent, false);
2409
Adam Powell82349c52011-08-23 13:53:56 -07002410 final Context context = getContext();
2411 final int targetSdk = context.getApplicationInfo().targetSdkVersion;
2412 final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
2413 final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
Dianne Hackborn955d8d62014-10-07 20:17:19 -07002414 final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP;
Adam Powell82349c52011-08-23 13:53:56 -07002415 final boolean targetHcNeedsOptions = context.getResources().getBoolean(
Alan Viverette40982d42014-07-25 17:48:55 -07002416 R.bool.target_honeycomb_needs_options_menu);
Adam Powell82349c52011-08-23 13:53:56 -07002417 final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
2418
2419 if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
Wale Ogunwale393b1c12014-10-18 16:22:01 -07002420 setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
Dianne Hackborn73ab6a42011-12-13 11:16:23 -08002421 } else {
Wale Ogunwale393b1c12014-10-18 16:22:01 -07002422 setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);
Daniel Sandlere02d8082010-10-08 15:13:22 -04002423 }
Adrian Roosea562512014-05-05 13:33:03 +02002424
Jorim Jaggi6e0ce282015-12-01 15:19:49 -08002425 if (!mForcedStatusBarColor) {
2426 mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
2427 }
2428 if (!mForcedNavigationBarColor) {
2429 mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
2430 }
2431
Adrian Roosea562512014-05-05 13:33:03 +02002432 // Non-floating windows on high end devices must put up decor beneath the system bars and
2433 // therefore must know about visibility changes of those.
2434 if (!mIsFloating && ActivityManager.isHighEndGfx()) {
2435 if (!targetPreL && a.getBoolean(
Alan Viverette40982d42014-07-25 17:48:55 -07002436 R.styleable.Window_windowDrawsSystemBarBackgrounds,
Adrian Roosea562512014-05-05 13:33:03 +02002437 false)) {
2438 setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
2439 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
2440 }
Adrian Roosea562512014-05-05 13:33:03 +02002441 }
Adrian Roosf4f84c92015-04-28 13:44:43 -07002442 if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) {
Adrian Roos75fa3852015-01-27 20:21:44 +01002443 decor.setSystemUiVisibility(
2444 decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
2445 }
Adrian Roosea562512014-05-05 13:33:03 +02002446
Dianne Hackborncfaf8872011-01-18 13:57:54 -08002447 if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
2448 >= android.os.Build.VERSION_CODES.HONEYCOMB) {
Dianne Hackbornef575752011-01-18 17:35:17 -08002449 if (a.getBoolean(
Alan Viverette40982d42014-07-25 17:48:55 -07002450 R.styleable.Window_windowCloseOnTouchOutside,
Dianne Hackbornef575752011-01-18 17:35:17 -08002451 false)) {
2452 setCloseOnTouchOutsideIfNotSet(true);
Dianne Hackborncfaf8872011-01-18 13:57:54 -08002453 }
2454 }
Alan Viveretteeb1d3792014-06-03 18:36:03 -07002455
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002456 WindowManager.LayoutParams params = getAttributes();
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002457
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002458 if (!hasSoftInputMode()) {
2459 params.softInputMode = a.getInt(
Alan Viverette40982d42014-07-25 17:48:55 -07002460 R.styleable.Window_windowSoftInputMode,
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002461 params.softInputMode);
2462 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002463
Alan Viverette40982d42014-07-25 17:48:55 -07002464 if (a.getBoolean(R.styleable.Window_backgroundDimEnabled,
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002465 mIsFloating)) {
2466 /* All dialogs should have the window dimmed */
2467 if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {
2468 params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
2469 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002470 if (!haveDimAmount()) {
2471 params.dimAmount = a.getFloat(
2472 android.R.styleable.Window_backgroundDimAmount, 0.5f);
2473 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002474 }
2475
2476 if (params.windowAnimations == 0) {
2477 params.windowAnimations = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07002478 R.styleable.Window_windowAnimationStyle, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002479 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002480
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002481 // The rest are only done if this window is not embedded; otherwise,
2482 // the values are inherited from our container.
2483 if (getContainer() == null) {
2484 if (mBackgroundDrawable == null) {
2485 if (mBackgroundResource == 0) {
2486 mBackgroundResource = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07002487 R.styleable.Window_windowBackground, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002488 }
2489 if (mFrameResource == 0) {
Alan Viverette40982d42014-07-25 17:48:55 -07002490 mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002491 }
Adam Powellf849a5e2014-09-11 15:09:36 -07002492 mBackgroundFallbackResource = a.getResourceId(
2493 R.styleable.Window_windowBackgroundFallback, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002494 if (false) {
2495 System.out.println("Background: "
2496 + Integer.toHexString(mBackgroundResource) + " Frame: "
2497 + Integer.toHexString(mFrameResource));
2498 }
2499 }
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002500 if (mLoadElevation) {
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -07002501 mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
2502 }
Alan Viverette40982d42014-07-25 17:48:55 -07002503 mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);
2504 mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002505 }
2506
2507 // Inflate the window decor.
2508
2509 int layoutResource;
2510 int features = getLocalFeatures();
2511 // System.out.println("Features: 0x" + Integer.toHexString(features));
Will Haldean Brownca6234e2014-02-12 10:23:41 -08002512 if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
Alan Viverette40982d42014-07-25 17:48:55 -07002513 layoutResource = R.layout.screen_swipe_dismiss;
Will Haldean Brownca6234e2014-02-12 10:23:41 -08002514 } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002515 if (mIsFloating) {
Adam Powell32aa2c92011-01-11 15:37:04 -08002516 TypedValue res = new TypedValue();
2517 getContext().getTheme().resolveAttribute(
Alan Viverette40982d42014-07-25 17:48:55 -07002518 R.attr.dialogTitleIconsDecorLayout, res, true);
Adam Powell32aa2c92011-01-11 15:37:04 -08002519 layoutResource = res.resourceId;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002520 } else {
Alan Viverette40982d42014-07-25 17:48:55 -07002521 layoutResource = R.layout.screen_title_icons;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002522 }
Adam Powellf4a6ec42010-08-24 14:18:10 -07002523 // XXX Remove this once action bar supports these features.
2524 removeFeature(FEATURE_ACTION_BAR);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002525 // System.out.println("Title Icons!");
Adam Powell6af97e12010-11-11 21:11:53 -08002526 } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
2527 && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002528 // Special case for a window with only a progress bar (and title).
2529 // XXX Need to have a no-title version of embedded windows.
Alan Viverette40982d42014-07-25 17:48:55 -07002530 layoutResource = R.layout.screen_progress;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002531 // System.out.println("Progress!");
2532 } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
2533 // Special case for a window with a custom title.
2534 // If the window is floating, we need a dialog layout
2535 if (mIsFloating) {
Adam Powell32aa2c92011-01-11 15:37:04 -08002536 TypedValue res = new TypedValue();
2537 getContext().getTheme().resolveAttribute(
Alan Viverette40982d42014-07-25 17:48:55 -07002538 R.attr.dialogCustomTitleDecorLayout, res, true);
Adam Powell32aa2c92011-01-11 15:37:04 -08002539 layoutResource = res.resourceId;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002540 } else {
Alan Viverette40982d42014-07-25 17:48:55 -07002541 layoutResource = R.layout.screen_custom_title;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002542 }
Adam Powellf4a6ec42010-08-24 14:18:10 -07002543 // XXX Remove this once action bar supports these features.
2544 removeFeature(FEATURE_ACTION_BAR);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002545 } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
2546 // If no other features and not embedded, only need a title.
2547 // If the window is floating, we need a dialog layout
2548 if (mIsFloating) {
Adam Powell32aa2c92011-01-11 15:37:04 -08002549 TypedValue res = new TypedValue();
2550 getContext().getTheme().resolveAttribute(
Alan Viverette40982d42014-07-25 17:48:55 -07002551 R.attr.dialogTitleDecorLayout, res, true);
Adam Powell32aa2c92011-01-11 15:37:04 -08002552 layoutResource = res.resourceId;
Adam Powell33b97432010-04-20 10:01:14 -07002553 } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
Adam Powelle021e6e2014-05-23 17:27:24 -07002554 layoutResource = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07002555 R.styleable.Window_windowActionBarFullscreenDecorLayout,
2556 R.layout.screen_action_bar);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002557 } else {
Alan Viverette40982d42014-07-25 17:48:55 -07002558 layoutResource = R.layout.screen_title;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002559 }
2560 // System.out.println("Title!");
Adam Powellf8419a02011-10-03 12:08:54 -07002561 } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
Alan Viverette40982d42014-07-25 17:48:55 -07002562 layoutResource = R.layout.screen_simple_overlay_action_mode;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002563 } else {
2564 // Embedded, so no decoration is needed.
Alan Viverette40982d42014-07-25 17:48:55 -07002565 layoutResource = R.layout.screen_simple;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002566 // System.out.println("Simple!");
2567 }
2568
2569 mDecor.startChanging();
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002570 mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002571
2572 ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
2573 if (contentParent == null) {
2574 throw new RuntimeException("Window couldn't find content container view");
2575 }
2576
2577 if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
2578 ProgressBar progress = getCircularProgressBar(false);
2579 if (progress != null) {
2580 progress.setIndeterminate(true);
2581 }
2582 }
2583
Will Haldean Brownca6234e2014-02-12 10:23:41 -08002584 if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
2585 registerSwipeCallbacks();
2586 }
2587
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002588 // Remaining setup -- of background and title -- that only applies
2589 // to top-level windows.
2590 if (getContainer() == null) {
Alan Viverette49a22e82014-07-12 20:01:27 -07002591 final Drawable background;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002592 if (mBackgroundResource != 0) {
Alan Viverette49a22e82014-07-12 20:01:27 -07002593 background = getContext().getDrawable(mBackgroundResource);
2594 } else {
2595 background = mBackgroundDrawable;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002596 }
Alan Viverette49a22e82014-07-12 20:01:27 -07002597 mDecor.setWindowBackground(background);
2598
2599 final Drawable frame;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002600 if (mFrameResource != 0) {
Alan Viverette49a22e82014-07-12 20:01:27 -07002601 frame = getContext().getDrawable(mFrameResource);
2602 } else {
2603 frame = null;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002604 }
Alan Viverette49a22e82014-07-12 20:01:27 -07002605 mDecor.setWindowFrame(frame);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002606
Alan Viverette49a22e82014-07-12 20:01:27 -07002607 mDecor.setElevation(mElevation);
Alan Viverette2c183332014-08-07 13:43:05 -07002608 mDecor.setClipToOutline(mClipToOutline);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002609
2610 if (mTitle != null) {
2611 setTitle(mTitle);
2612 }
Alan Viverette49a22e82014-07-12 20:01:27 -07002613
2614 if (mTitleColor == 0) {
2615 mTitleColor = mTextColor;
2616 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002617 setTitleColor(mTitleColor);
2618 }
2619
2620 mDecor.finishChanging();
2621
2622 return contentParent;
2623 }
2624
Dianne Hackborncfaf8872011-01-18 13:57:54 -08002625 /** @hide */
2626 public void alwaysReadCloseOnTouchAttr() {
2627 mAlwaysReadCloseOnTouchAttr = true;
2628 }
2629
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002630 private void installDecor() {
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -07002631 mForceDecorInstall = false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002632 if (mDecor == null) {
Stefan Kuhne61b47bb2015-07-28 14:04:25 -07002633 mDecor = generateDecor(-1);
Adam Powell00f4d982010-03-24 11:17:03 -07002634 mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002635 mDecor.setIsRootNamespace(true);
Adam Powell4b6d93f2012-09-18 18:34:08 -07002636 if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
2637 mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
2638 }
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07002639 } else {
2640 mDecor.setWindow(this);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002641 }
2642 if (mContentParent == null) {
2643 mContentParent = generateLayout(mDecor);
2644
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002645 // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
2646 mDecor.makeOptionalFitsSystemWindows();
2647
Adam Powell4369e7d2014-05-17 14:16:08 -07002648 final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
Alan Viverette40982d42014-07-25 17:48:55 -07002649 R.id.decor_content_parent);
Adam Powell4369e7d2014-05-17 14:16:08 -07002650
2651 if (decorContentParent != null) {
2652 mDecorContentParent = decorContentParent;
2653 mDecorContentParent.setWindowCallback(getCallback());
2654 if (mDecorContentParent.getTitle() == null) {
2655 mDecorContentParent.setWindowTitle(mTitle);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002656 }
Adam Powell9b4bee02011-04-27 19:24:47 -07002657
Adam Powell4369e7d2014-05-17 14:16:08 -07002658 final int localFeatures = getLocalFeatures();
2659 for (int i = 0; i < FEATURE_MAX; i++) {
2660 if ((localFeatures & (1 << i)) != 0) {
2661 mDecorContentParent.initFeature(i);
Adam Powell9b0dc282013-07-31 13:58:43 -07002662 }
Adam Powell4369e7d2014-05-17 14:16:08 -07002663 }
Adam Powell9b0dc282013-07-31 13:58:43 -07002664
Adam Powell4369e7d2014-05-17 14:16:08 -07002665 mDecorContentParent.setUiOptions(mUiOptions);
Adam Powell640a66e2011-04-29 10:18:53 -07002666
Adam Powell4369e7d2014-05-17 14:16:08 -07002667 if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
2668 (mIconRes != 0 && !mDecorContentParent.hasIcon())) {
2669 mDecorContentParent.setIcon(mIconRes);
2670 } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
2671 mIconRes == 0 && !mDecorContentParent.hasIcon()) {
2672 mDecorContentParent.setIcon(
2673 getContext().getPackageManager().getDefaultActivityIcon());
2674 mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
2675 }
2676 if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
2677 (mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
2678 mDecorContentParent.setLogo(mLogoRes);
2679 }
Adam Powell9b4bee02011-04-27 19:24:47 -07002680
Adam Powell31c91c82014-08-22 17:20:00 -07002681 // Invalidate if the panel menu hasn't been created before this.
2682 // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
Adam Powell4369e7d2014-05-17 14:16:08 -07002683 // being called in the middle of onCreate or similar.
Adam Powell31c91c82014-08-22 17:20:00 -07002684 // A pending invalidation will typically be resolved before the posted message
2685 // would run normally in order to satisfy instance state restoration.
2686 PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
Jorim Jaggia16cc152015-06-01 16:55:05 -07002687 if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) {
Adam Powell31c91c82014-08-22 17:20:00 -07002688 invalidatePanelMenu(FEATURE_ACTION_BAR);
2689 }
Adam Powell4369e7d2014-05-17 14:16:08 -07002690 } else {
Alan Viverette891c9ee2016-01-08 13:43:15 -05002691 mTitleView = (TextView) findViewById(R.id.title);
Adam Powell4369e7d2014-05-17 14:16:08 -07002692 if (mTitleView != null) {
Adam Powell4369e7d2014-05-17 14:16:08 -07002693 if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
Alan Viverette891c9ee2016-01-08 13:43:15 -05002694 final View titleContainer = findViewById(R.id.title_container);
Adam Powell4369e7d2014-05-17 14:16:08 -07002695 if (titleContainer != null) {
2696 titleContainer.setVisibility(View.GONE);
2697 } else {
2698 mTitleView.setVisibility(View.GONE);
2699 }
Alan Viverette891c9ee2016-01-08 13:43:15 -05002700 mContentParent.setForeground(null);
Adam Powell4369e7d2014-05-17 14:16:08 -07002701 } else {
2702 mTitleView.setText(mTitle);
2703 }
Adam Powell33b97432010-04-20 10:01:14 -07002704 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002705 }
Adam Powell18e905f2013-10-24 14:27:48 -07002706
Adam Powellf849a5e2014-09-11 15:09:36 -07002707 if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
2708 mDecor.setBackgroundFallback(mBackgroundFallbackResource);
2709 }
2710
Adam Powell18e905f2013-10-24 14:27:48 -07002711 // Only inflate or create a new TransitionManager if the caller hasn't
2712 // already set a custom one.
George Mount9826f632014-09-11 08:50:09 -07002713 if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
George Mount31a21722014-03-24 17:44:36 -07002714 if (mTransitionManager == null) {
2715 final int transitionRes = getWindowStyle().getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07002716 R.styleable.Window_windowContentTransitionManager,
George Mount31a21722014-03-24 17:44:36 -07002717 0);
2718 if (transitionRes != 0) {
2719 final TransitionInflater inflater = TransitionInflater.from(getContext());
2720 mTransitionManager = inflater.inflateTransitionManager(transitionRes,
2721 mContentParent);
2722 } else {
2723 mTransitionManager = new TransitionManager();
2724 }
2725 }
2726
George Mount68f96d82014-07-31 13:13:10 -07002727 mEnterTransition = getTransition(mEnterTransition, null,
Alan Viverette40982d42014-07-25 17:48:55 -07002728 R.styleable.Window_windowEnterTransition);
George Mount68f96d82014-07-31 13:13:10 -07002729 mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,
2730 R.styleable.Window_windowReturnTransition);
2731 mExitTransition = getTransition(mExitTransition, null,
Alan Viverette40982d42014-07-25 17:48:55 -07002732 R.styleable.Window_windowExitTransition);
George Mount68f96d82014-07-31 13:13:10 -07002733 mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,
2734 R.styleable.Window_windowReenterTransition);
2735 mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null,
Alan Viverette40982d42014-07-25 17:48:55 -07002736 R.styleable.Window_windowSharedElementEnterTransition);
George Mount68f96d82014-07-31 13:13:10 -07002737 mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition,
2738 USE_DEFAULT_TRANSITION,
2739 R.styleable.Window_windowSharedElementReturnTransition);
2740 mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null,
Alan Viverette40982d42014-07-25 17:48:55 -07002741 R.styleable.Window_windowSharedElementExitTransition);
George Mount68f96d82014-07-31 13:13:10 -07002742 mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition,
2743 USE_DEFAULT_TRANSITION,
2744 R.styleable.Window_windowSharedElementReenterTransition);
George Mount31a21722014-03-24 17:44:36 -07002745 if (mAllowEnterTransitionOverlap == null) {
2746 mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(
George Mount68f96d82014-07-31 13:13:10 -07002747 R.styleable.Window_windowAllowEnterTransitionOverlap, true);
George Mount31a21722014-03-24 17:44:36 -07002748 }
George Mountc03da0e2014-08-22 17:04:02 -07002749 if (mAllowReturnTransitionOverlap == null) {
2750 mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(
2751 R.styleable.Window_windowAllowReturnTransitionOverlap, true);
Adam Powell18e905f2013-10-24 14:27:48 -07002752 }
George Mounted1e01d2014-06-05 13:49:12 -07002753 if (mBackgroundFadeDurationMillis < 0) {
2754 mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
George Mount68f96d82014-07-31 13:13:10 -07002755 R.styleable.Window_windowTransitionBackgroundFadeDuration,
George Mounted1e01d2014-06-05 13:49:12 -07002756 DEFAULT_BACKGROUND_FADE_DURATION_MS);
2757 }
George Mountb89d5cc2014-08-18 16:50:50 -07002758 if (mSharedElementsUseOverlay == null) {
2759 mSharedElementsUseOverlay = getWindowStyle().getBoolean(
2760 R.styleable.Window_windowSharedElementsUseOverlay, true);
2761 }
Adam Powell18e905f2013-10-24 14:27:48 -07002762 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002763 }
2764 }
2765
George Mount68f96d82014-07-31 13:13:10 -07002766 private Transition getTransition(Transition currentValue, Transition defaultValue, int id) {
2767 if (currentValue != defaultValue) {
George Mount31a21722014-03-24 17:44:36 -07002768 return currentValue;
2769 }
2770 int transitionId = getWindowStyle().getResourceId(id, -1);
George Mount68f96d82014-07-31 13:13:10 -07002771 Transition transition = defaultValue;
Alan Viverette40982d42014-07-25 17:48:55 -07002772 if (transitionId != -1 && transitionId != R.transition.no_transition) {
George Mount31a21722014-03-24 17:44:36 -07002773 TransitionInflater inflater = TransitionInflater.from(getContext());
2774 transition = inflater.inflateTransition(transitionId);
George Mount7f151642014-08-18 16:24:21 -07002775 if (transition instanceof TransitionSet &&
2776 ((TransitionSet)transition).getTransitionCount() == 0) {
2777 transition = null;
2778 }
George Mount31a21722014-03-24 17:44:36 -07002779 }
2780 return transition;
2781 }
2782
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002783 private Drawable loadImageURI(Uri uri) {
2784 try {
Alan Viverettead3c4a12014-06-02 17:12:58 -07002785 return Drawable.createFromStream(
2786 getContext().getContentResolver().openInputStream(uri), null);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002787 } catch (Exception e) {
2788 Log.w(TAG, "Unable to open content: " + uri);
2789 }
2790 return null;
2791 }
2792
2793 private DrawableFeatureState getDrawableState(int featureId, boolean required) {
2794 if ((getFeatures() & (1 << featureId)) == 0) {
2795 if (!required) {
2796 return null;
2797 }
2798 throw new RuntimeException("The feature has not been requested");
2799 }
2800
2801 DrawableFeatureState[] ar;
2802 if ((ar = mDrawables) == null || ar.length <= featureId) {
2803 DrawableFeatureState[] nar = new DrawableFeatureState[featureId + 1];
2804 if (ar != null) {
2805 System.arraycopy(ar, 0, nar, 0, ar.length);
2806 }
2807 mDrawables = ar = nar;
2808 }
2809
2810 DrawableFeatureState st = ar[featureId];
2811 if (st == null) {
2812 ar[featureId] = st = new DrawableFeatureState(featureId);
2813 }
2814 return st;
2815 }
2816
2817 /**
2818 * Gets a panel's state based on its feature ID.
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002819 *
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002820 * @param featureId The feature ID of the panel.
2821 * @param required Whether the panel is required (if it is required and it
2822 * isn't in our features, this throws an exception).
2823 * @return The panel state.
2824 */
Wale Ogunwale8804af22015-11-17 09:18:15 -08002825 PanelFeatureState getPanelState(int featureId, boolean required) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002826 return getPanelState(featureId, required, null);
2827 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002828
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002829 /**
2830 * Gets a panel's state based on its feature ID.
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002831 *
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002832 * @param featureId The feature ID of the panel.
2833 * @param required Whether the panel is required (if it is required and it
2834 * isn't in our features, this throws an exception).
2835 * @param convertPanelState Optional: If the panel state does not exist, use
2836 * this as the panel state.
2837 * @return The panel state.
2838 */
2839 private PanelFeatureState getPanelState(int featureId, boolean required,
2840 PanelFeatureState convertPanelState) {
2841 if ((getFeatures() & (1 << featureId)) == 0) {
2842 if (!required) {
2843 return null;
2844 }
2845 throw new RuntimeException("The feature has not been requested");
2846 }
2847
2848 PanelFeatureState[] ar;
2849 if ((ar = mPanels) == null || ar.length <= featureId) {
2850 PanelFeatureState[] nar = new PanelFeatureState[featureId + 1];
2851 if (ar != null) {
2852 System.arraycopy(ar, 0, nar, 0, ar.length);
2853 }
2854 mPanels = ar = nar;
2855 }
2856
2857 PanelFeatureState st = ar[featureId];
2858 if (st == null) {
2859 ar[featureId] = st = (convertPanelState != null)
2860 ? convertPanelState
2861 : new PanelFeatureState(featureId);
2862 }
2863 return st;
2864 }
2865
2866 @Override
2867 public final void setChildDrawable(int featureId, Drawable drawable) {
2868 DrawableFeatureState st = getDrawableState(featureId, true);
2869 st.child = drawable;
2870 updateDrawable(featureId, st, false);
2871 }
2872
2873 @Override
2874 public final void setChildInt(int featureId, int value) {
2875 updateInt(featureId, value, false);
2876 }
2877
2878 @Override
2879 public boolean isShortcutKey(int keyCode, KeyEvent event) {
Jose Lima7a22fc62015-01-23 17:24:22 -08002880 PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
2881 return st != null && st.menu != null && st.menu.isShortcutKey(keyCode, event);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002882 }
2883
2884 private void updateDrawable(int featureId, DrawableFeatureState st, boolean fromResume) {
2885 // Do nothing if the decor is not yet installed... an update will
2886 // need to be forced when we eventually become active.
2887 if (mContentParent == null) {
2888 return;
2889 }
2890
2891 final int featureMask = 1 << featureId;
2892
2893 if ((getFeatures() & featureMask) == 0 && !fromResume) {
2894 return;
2895 }
2896
2897 Drawable drawable = null;
2898 if (st != null) {
2899 drawable = st.child;
2900 if (drawable == null)
2901 drawable = st.local;
2902 if (drawable == null)
2903 drawable = st.def;
2904 }
2905 if ((getLocalFeatures() & featureMask) == 0) {
2906 if (getContainer() != null) {
2907 if (isActive() || fromResume) {
2908 getContainer().setChildDrawable(featureId, drawable);
2909 }
2910 }
2911 } else if (st != null && (st.cur != drawable || st.curAlpha != st.alpha)) {
2912 // System.out.println("Drawable changed: old=" + st.cur
2913 // + ", new=" + drawable);
2914 st.cur = drawable;
2915 st.curAlpha = st.alpha;
2916 onDrawableChanged(featureId, drawable, st.alpha);
2917 }
2918 }
2919
2920 private void updateInt(int featureId, int value, boolean fromResume) {
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08002921
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002922 // Do nothing if the decor is not yet installed... an update will
2923 // need to be forced when we eventually become active.
2924 if (mContentParent == null) {
2925 return;
2926 }
2927
2928 final int featureMask = 1 << featureId;
2929
2930 if ((getFeatures() & featureMask) == 0 && !fromResume) {
2931 return;
2932 }
2933
2934 if ((getLocalFeatures() & featureMask) == 0) {
2935 if (getContainer() != null) {
2936 getContainer().setChildInt(featureId, value);
2937 }
2938 } else {
2939 onIntChanged(featureId, value);
2940 }
2941 }
2942
2943 private ImageView getLeftIconView() {
2944 if (mLeftIconView != null) {
2945 return mLeftIconView;
2946 }
2947 if (mContentParent == null) {
2948 installDecor();
2949 }
Alan Viverette40982d42014-07-25 17:48:55 -07002950 return (mLeftIconView = (ImageView)findViewById(R.id.left_icon));
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002951 }
2952
Adrian Roosea562512014-05-05 13:33:03 +02002953 @Override
2954 protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
2955 super.dispatchWindowAttributesChanged(attrs);
2956 if (mDecor != null) {
Adrian Roos05054bd2014-10-27 17:04:10 +01002957 mDecor.updateColorViews(null /* insets */, true /* animate */);
Adrian Roosea562512014-05-05 13:33:03 +02002958 }
2959 }
2960
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002961 private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) {
2962 if (mCircularProgressBar != null) {
2963 return mCircularProgressBar;
2964 }
2965 if (mContentParent == null && shouldInstallDecor) {
2966 installDecor();
2967 }
Alan Viverette40982d42014-07-25 17:48:55 -07002968 mCircularProgressBar = (ProgressBar) findViewById(R.id.progress_circular);
Adam Powell6af97e12010-11-11 21:11:53 -08002969 if (mCircularProgressBar != null) {
2970 mCircularProgressBar.setVisibility(View.INVISIBLE);
2971 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002972 return mCircularProgressBar;
2973 }
2974
2975 private ProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) {
2976 if (mHorizontalProgressBar != null) {
2977 return mHorizontalProgressBar;
2978 }
2979 if (mContentParent == null && shouldInstallDecor) {
2980 installDecor();
2981 }
Alan Viverette40982d42014-07-25 17:48:55 -07002982 mHorizontalProgressBar = (ProgressBar) findViewById(R.id.progress_horizontal);
Adam Powell6af97e12010-11-11 21:11:53 -08002983 if (mHorizontalProgressBar != null) {
2984 mHorizontalProgressBar.setVisibility(View.INVISIBLE);
2985 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002986 return mHorizontalProgressBar;
2987 }
2988
2989 private ImageView getRightIconView() {
2990 if (mRightIconView != null) {
2991 return mRightIconView;
2992 }
2993 if (mContentParent == null) {
2994 installDecor();
2995 }
Alan Viverette40982d42014-07-25 17:48:55 -07002996 return (mRightIconView = (ImageView)findViewById(R.id.right_icon));
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08002997 }
2998
Will Haldean Brownca6234e2014-02-12 10:23:41 -08002999 private void registerSwipeCallbacks() {
3000 SwipeDismissLayout swipeDismiss =
Alan Viverette40982d42014-07-25 17:48:55 -07003001 (SwipeDismissLayout) findViewById(R.id.content);
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003002 swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
3003 @Override
3004 public void onDismissed(SwipeDismissLayout layout) {
Stefan Kuhne1b420572015-08-07 10:50:19 -07003005 dispatchOnWindowDismissed(false /*finishTask*/);
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003006 }
3007 });
3008 swipeDismiss.setOnSwipeProgressChangedListener(
3009 new SwipeDismissLayout.OnSwipeProgressChangedListener() {
Mark Renoufd0761212014-04-30 20:50:30 -04003010 private static final float ALPHA_DECREASE = 0.5f;
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003011 private boolean mIsTranslucent = false;
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003012 @Override
3013 public void onSwipeProgressChanged(
3014 SwipeDismissLayout layout, float progress, float translate) {
3015 WindowManager.LayoutParams newParams = getAttributes();
3016 newParams.x = (int) translate;
Mark Renoufd0761212014-04-30 20:50:30 -04003017 newParams.alpha = 1 - (progress * ALPHA_DECREASE);
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003018 setAttributes(newParams);
3019
3020 int flags = 0;
3021 if (newParams.x == 0) {
3022 flags = FLAG_FULLSCREEN;
3023 } else {
3024 flags = FLAG_LAYOUT_NO_LIMITS;
3025 }
3026 setFlags(flags, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
3027 }
3028
3029 @Override
3030 public void onSwipeCancelled(SwipeDismissLayout layout) {
3031 WindowManager.LayoutParams newParams = getAttributes();
3032 newParams.x = 0;
Mindy Pereirab0ea4842014-04-17 14:01:04 -07003033 newParams.alpha = 1;
Will Haldean Brownca6234e2014-02-12 10:23:41 -08003034 setAttributes(newParams);
3035 setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
3036 }
3037 });
3038 }
3039
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003040 /**
3041 * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)}
3042 * callback. This method will grab whatever extra state is needed for the
3043 * callback that isn't given in the parameters. If the panel is not open,
3044 * this will not perform the callback.
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003045 *
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003046 * @param featureId Feature ID of the panel that was closed. Must be given.
3047 * @param panel Panel that was closed. Optional but useful if there is no
3048 * menu given.
3049 * @param menu The menu that was closed. Optional, but give if you have.
3050 */
3051 private void callOnPanelClosed(int featureId, PanelFeatureState panel, Menu menu) {
3052 final Callback cb = getCallback();
3053 if (cb == null)
3054 return;
3055
3056 // Try to get a menu
3057 if (menu == null) {
3058 // Need a panel to grab the menu, so try to get that
3059 if (panel == null) {
3060 if ((featureId >= 0) && (featureId < mPanels.length)) {
3061 panel = mPanels[featureId];
3062 }
3063 }
3064
3065 if (panel != null) {
3066 // menu still may be null, which is okay--we tried our best
3067 menu = panel.menu;
3068 }
3069 }
3070
3071 // If the panel is not open, do not callback
3072 if ((panel != null) && (!panel.isOpen))
3073 return;
3074
Dianne Hackbornb66ad572011-03-01 17:10:30 -08003075 if (!isDestroyed()) {
3076 cb.onPanelClosed(featureId, menu);
3077 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003078 }
3079
3080 /**
3081 * Helper method for adding launch-search to most applications. Opens the
3082 * search window using default settings.
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003083 *
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003084 * @return true if search window opened
3085 */
Tim Kilbourn6a975b32015-04-09 17:14:34 -07003086 private boolean launchDefaultSearch(KeyEvent event) {
Dianne Hackbornfdf5b352014-10-08 17:43:48 -07003087 boolean result;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003088 final Callback cb = getCallback();
Dianne Hackbornb66ad572011-03-01 17:10:30 -08003089 if (cb == null || isDestroyed()) {
Dianne Hackbornfdf5b352014-10-08 17:43:48 -07003090 result = false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003091 } else {
Karl Rosaen323216b2009-07-20 14:00:29 -07003092 sendCloseSystemWindows("search");
Tim Kilbourn6a975b32015-04-09 17:14:34 -07003093 int deviceId = event.getDeviceId();
3094 SearchEvent searchEvent = null;
3095 if (deviceId != 0) {
3096 searchEvent = new SearchEvent(InputDevice.getDevice(deviceId));
3097 }
Adam Powell97900342015-04-15 13:12:52 -07003098 try {
3099 result = cb.onSearchRequested(searchEvent);
3100 } catch (AbstractMethodError e) {
3101 Log.e(TAG, "WindowCallback " + cb.getClass().getName() + " does not implement"
3102 + " method onSearchRequested(SearchEvent); fa", e);
3103 result = cb.onSearchRequested();
3104 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003105 }
Dianne Hackbornfdf5b352014-10-08 17:43:48 -07003106 if (!result && (getContext().getResources().getConfiguration().uiMode
3107 & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) {
3108 // On TVs, if the app doesn't implement search, we want to launch assist.
Tim Kilbourn0e5f1102015-06-05 16:18:09 -07003109 Bundle args = new Bundle();
3110 args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, event.getDeviceId());
Dianne Hackbornfdf5b352014-10-08 17:43:48 -07003111 return ((SearchManager)getContext().getSystemService(Context.SEARCH_SERVICE))
Jorim Jaggi165ce062015-07-06 16:18:11 -07003112 .launchLegacyAssist(null, UserHandle.myUserId(), args);
Dianne Hackbornfdf5b352014-10-08 17:43:48 -07003113 }
3114 return result;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003115 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003116
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003117 @Override
3118 public void setVolumeControlStream(int streamType) {
3119 mVolumeControlStreamType = streamType;
3120 }
3121
3122 @Override
3123 public int getVolumeControlStream() {
3124 return mVolumeControlStreamType;
3125 }
3126
RoboErik55011652014-07-09 15:05:53 -07003127 @Override
3128 public void setMediaController(MediaController controller) {
3129 mMediaController = controller;
3130 }
3131
3132 @Override
3133 public MediaController getMediaController() {
3134 return mMediaController;
3135 }
3136
George Mount31a21722014-03-24 17:44:36 -07003137 @Override
3138 public void setEnterTransition(Transition enterTransition) {
3139 mEnterTransition = enterTransition;
3140 }
3141
3142 @Override
George Mount68f96d82014-07-31 13:13:10 -07003143 public void setReturnTransition(Transition transition) {
3144 mReturnTransition = transition;
3145 }
3146
3147 @Override
George Mount31a21722014-03-24 17:44:36 -07003148 public void setExitTransition(Transition exitTransition) {
3149 mExitTransition = exitTransition;
3150 }
3151
3152 @Override
George Mount68f96d82014-07-31 13:13:10 -07003153 public void setReenterTransition(Transition transition) {
3154 mReenterTransition = transition;
3155 }
3156
3157 @Override
George Mount31a21722014-03-24 17:44:36 -07003158 public void setSharedElementEnterTransition(Transition sharedElementEnterTransition) {
3159 mSharedElementEnterTransition = sharedElementEnterTransition;
3160 }
3161
3162 @Override
George Mount68f96d82014-07-31 13:13:10 -07003163 public void setSharedElementReturnTransition(Transition transition) {
3164 mSharedElementReturnTransition = transition;
3165 }
3166
3167 @Override
George Mount31a21722014-03-24 17:44:36 -07003168 public void setSharedElementExitTransition(Transition sharedElementExitTransition) {
3169 mSharedElementExitTransition = sharedElementExitTransition;
3170 }
3171
3172 @Override
George Mount68f96d82014-07-31 13:13:10 -07003173 public void setSharedElementReenterTransition(Transition transition) {
3174 mSharedElementReenterTransition = transition;
3175 }
3176
3177 @Override
George Mount31a21722014-03-24 17:44:36 -07003178 public Transition getEnterTransition() {
3179 return mEnterTransition;
3180 }
3181
3182 @Override
George Mount68f96d82014-07-31 13:13:10 -07003183 public Transition getReturnTransition() {
3184 return mReturnTransition == USE_DEFAULT_TRANSITION ? getEnterTransition()
3185 : mReturnTransition;
3186 }
3187
3188 @Override
George Mount31a21722014-03-24 17:44:36 -07003189 public Transition getExitTransition() {
3190 return mExitTransition;
3191 }
3192
3193 @Override
George Mount68f96d82014-07-31 13:13:10 -07003194 public Transition getReenterTransition() {
3195 return mReenterTransition == USE_DEFAULT_TRANSITION ? getExitTransition()
3196 : mReenterTransition;
3197 }
3198
3199 @Override
George Mount31a21722014-03-24 17:44:36 -07003200 public Transition getSharedElementEnterTransition() {
3201 return mSharedElementEnterTransition;
3202 }
3203
3204 @Override
George Mount68f96d82014-07-31 13:13:10 -07003205 public Transition getSharedElementReturnTransition() {
3206 return mSharedElementReturnTransition == USE_DEFAULT_TRANSITION
3207 ? getSharedElementEnterTransition() : mSharedElementReturnTransition;
3208 }
3209
3210 @Override
George Mount31a21722014-03-24 17:44:36 -07003211 public Transition getSharedElementExitTransition() {
3212 return mSharedElementExitTransition;
3213 }
3214
3215 @Override
George Mount68f96d82014-07-31 13:13:10 -07003216 public Transition getSharedElementReenterTransition() {
3217 return mSharedElementReenterTransition == USE_DEFAULT_TRANSITION
3218 ? getSharedElementExitTransition() : mSharedElementReenterTransition;
3219 }
3220
3221 @Override
George Mount31a21722014-03-24 17:44:36 -07003222 public void setAllowEnterTransitionOverlap(boolean allow) {
3223 mAllowEnterTransitionOverlap = allow;
3224 }
3225
3226 @Override
3227 public boolean getAllowEnterTransitionOverlap() {
3228 return (mAllowEnterTransitionOverlap == null) ? true : mAllowEnterTransitionOverlap;
3229 }
3230
3231 @Override
George Mountc03da0e2014-08-22 17:04:02 -07003232 public void setAllowReturnTransitionOverlap(boolean allowExitTransitionOverlap) {
3233 mAllowReturnTransitionOverlap = allowExitTransitionOverlap;
George Mount31a21722014-03-24 17:44:36 -07003234 }
3235
3236 @Override
George Mountc03da0e2014-08-22 17:04:02 -07003237 public boolean getAllowReturnTransitionOverlap() {
3238 return (mAllowReturnTransitionOverlap == null) ? true : mAllowReturnTransitionOverlap;
George Mount31a21722014-03-24 17:44:36 -07003239 }
3240
George Mounted1e01d2014-06-05 13:49:12 -07003241 @Override
3242 public long getTransitionBackgroundFadeDuration() {
3243 return (mBackgroundFadeDurationMillis < 0) ? DEFAULT_BACKGROUND_FADE_DURATION_MS
3244 : mBackgroundFadeDurationMillis;
3245 }
3246
3247 @Override
3248 public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) {
3249 if (fadeDurationMillis < 0) {
3250 throw new IllegalArgumentException("negative durations are not allowed");
3251 }
3252 mBackgroundFadeDurationMillis = fadeDurationMillis;
3253 }
3254
George Mountb89d5cc2014-08-18 16:50:50 -07003255 @Override
3256 public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) {
3257 mSharedElementsUseOverlay = sharedElementsUseOverlay;
3258 }
3259
3260 @Override
3261 public boolean getSharedElementsUseOverlay() {
3262 return (mSharedElementsUseOverlay == null) ? true : mSharedElementsUseOverlay;
3263 }
3264
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003265 private static final class DrawableFeatureState {
3266 DrawableFeatureState(int _featureId) {
3267 featureId = _featureId;
3268 }
3269
3270 final int featureId;
3271
3272 int resid;
3273
3274 Uri uri;
3275
3276 Drawable local;
3277
3278 Drawable child;
3279
3280 Drawable def;
3281
3282 Drawable cur;
3283
3284 int alpha = 255;
3285
3286 int curAlpha = 255;
3287 }
3288
Wale Ogunwale8804af22015-11-17 09:18:15 -08003289 static final class PanelFeatureState {
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003290
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003291 /** Feature ID for this panel. */
3292 int featureId;
3293
3294 // Information pulled from the style for this panel.
3295
3296 int background;
3297
3298 /** The background when the panel spans the entire available width. */
3299 int fullBackground;
3300
3301 int gravity;
3302
3303 int x;
3304
3305 int y;
3306
3307 int windowAnimations;
3308
3309 /** Dynamic state of the panel. */
3310 DecorView decorView;
3311
3312 /** The panel that was returned by onCreatePanelView(). */
3313 View createdPanelView;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003314
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003315 /** The panel that we are actually showing. */
3316 View shownPanelView;
3317
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003318 /** Use {@link #setMenu} to set this. */
Adam Powell696cba52011-03-29 10:38:16 -07003319 MenuBuilder menu;
3320
3321 IconMenuPresenter iconMenuPresenter;
Adam Powelldfee59a2011-08-05 20:48:30 -07003322 ListMenuPresenter listMenuPresenter;
3323
3324 /** true if this menu will show in single-list compact mode */
3325 boolean isCompact;
3326
3327 /** Theme resource ID for list elements of the panel menu */
3328 int listPresenterTheme;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003329
3330 /**
3331 * Whether the panel has been prepared (see
3332 * {@link PhoneWindow#preparePanel}).
3333 */
3334 boolean isPrepared;
3335
3336 /**
3337 * Whether an item's action has been performed. This happens in obvious
3338 * scenarios (user clicks on menu item), but can also happen with
3339 * chording menu+(shortcut key).
3340 */
3341 boolean isHandled;
3342
3343 boolean isOpen;
3344
3345 /**
3346 * True if the menu is in expanded mode, false if the menu is in icon
3347 * mode
3348 */
3349 boolean isInExpandedMode;
3350
3351 public boolean qwertyMode;
3352
3353 boolean refreshDecorView;
3354
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07003355 boolean refreshMenuContent;
Alan Viveretteeb1d3792014-06-03 18:36:03 -07003356
Dianne Hackbornd0071442009-09-25 01:35:29 -07003357 boolean wasLastOpen;
Alan Viveretteeb1d3792014-06-03 18:36:03 -07003358
Dianne Hackbornd0071442009-09-25 01:35:29 -07003359 boolean wasLastExpanded;
Alan Viveretteeb1d3792014-06-03 18:36:03 -07003360
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003361 /**
3362 * Contains the state of the menu when told to freeze.
3363 */
3364 Bundle frozenMenuState;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003365
Adam Powell038f1c82011-07-21 14:28:10 -07003366 /**
3367 * Contains the state of associated action views when told to freeze.
3368 * These are saved across invalidations.
3369 */
3370 Bundle frozenActionViewState;
3371
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003372 PanelFeatureState(int featureId) {
3373 this.featureId = featureId;
3374
3375 refreshDecorView = false;
3376 }
3377
Adam Powelldfee59a2011-08-05 20:48:30 -07003378 public boolean isInListMode() {
3379 return isInExpandedMode || isCompact;
3380 }
3381
Adam Powell526b9312011-04-22 15:42:05 -07003382 public boolean hasPanelItems() {
3383 if (shownPanelView == null) return false;
Adam Powell4fd8d5332011-08-17 14:54:41 -07003384 if (createdPanelView != null) return true;
Adam Powell526b9312011-04-22 15:42:05 -07003385
Adam Powelldfee59a2011-08-05 20:48:30 -07003386 if (isCompact || isInExpandedMode) {
3387 return listMenuPresenter.getAdapter().getCount() > 0;
Adam Powell526b9312011-04-22 15:42:05 -07003388 } else {
3389 return ((ViewGroup) shownPanelView).getChildCount() > 0;
3390 }
3391 }
3392
Adam Powell696cba52011-03-29 10:38:16 -07003393 /**
3394 * Unregister and free attached MenuPresenters. They will be recreated as needed.
3395 */
3396 public void clearMenuPresenters() {
3397 if (menu != null) {
3398 menu.removeMenuPresenter(iconMenuPresenter);
Adam Powelldfee59a2011-08-05 20:48:30 -07003399 menu.removeMenuPresenter(listMenuPresenter);
Adam Powell696cba52011-03-29 10:38:16 -07003400 }
3401 iconMenuPresenter = null;
Adam Powelldfee59a2011-08-05 20:48:30 -07003402 listMenuPresenter = null;
Adam Powell696cba52011-03-29 10:38:16 -07003403 }
3404
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003405 void setStyle(Context context) {
Alan Viverette40982d42014-07-25 17:48:55 -07003406 TypedArray a = context.obtainStyledAttributes(R.styleable.Theme);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003407 background = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07003408 R.styleable.Theme_panelBackground, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003409 fullBackground = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07003410 R.styleable.Theme_panelFullBackground, 0);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003411 windowAnimations = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07003412 R.styleable.Theme_windowAnimationStyle, 0);
Adam Powelldfee59a2011-08-05 20:48:30 -07003413 isCompact = a.getBoolean(
Alan Viverette40982d42014-07-25 17:48:55 -07003414 R.styleable.Theme_panelMenuIsCompact, false);
Adam Powelldfee59a2011-08-05 20:48:30 -07003415 listPresenterTheme = a.getResourceId(
Alan Viverette40982d42014-07-25 17:48:55 -07003416 R.styleable.Theme_panelMenuListTheme,
3417 R.style.Theme_ExpandedMenu);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003418 a.recycle();
3419 }
3420
Adam Powell696cba52011-03-29 10:38:16 -07003421 void setMenu(MenuBuilder menu) {
Adam Powell1d07e162011-09-07 20:46:24 -07003422 if (menu == this.menu) return;
3423
3424 if (this.menu != null) {
3425 this.menu.removeMenuPresenter(iconMenuPresenter);
3426 this.menu.removeMenuPresenter(listMenuPresenter);
3427 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003428 this.menu = menu;
Adam Powell1d07e162011-09-07 20:46:24 -07003429 if (menu != null) {
3430 if (iconMenuPresenter != null) menu.addMenuPresenter(iconMenuPresenter);
3431 if (listMenuPresenter != null) menu.addMenuPresenter(listMenuPresenter);
3432 }
Adam Powell696cba52011-03-29 10:38:16 -07003433 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003434
Adam Powell538e5652011-10-11 13:47:08 -07003435 MenuView getListMenuView(Context context, MenuPresenter.Callback cb) {
Adam Powell696cba52011-03-29 10:38:16 -07003436 if (menu == null) return null;
3437
Adam Powelldfee59a2011-08-05 20:48:30 -07003438 if (!isCompact) {
Adam Powell538e5652011-10-11 13:47:08 -07003439 getIconMenuView(context, cb); // Need this initialized to know where our offset goes
Adam Powell696cba52011-03-29 10:38:16 -07003440 }
3441
Adam Powelldfee59a2011-08-05 20:48:30 -07003442 if (listMenuPresenter == null) {
3443 listMenuPresenter = new ListMenuPresenter(
Alan Viverette40982d42014-07-25 17:48:55 -07003444 R.layout.list_menu_item_layout, listPresenterTheme);
Adam Powelldfee59a2011-08-05 20:48:30 -07003445 listMenuPresenter.setCallback(cb);
Alan Viverette40982d42014-07-25 17:48:55 -07003446 listMenuPresenter.setId(R.id.list_menu_presenter);
Adam Powelldfee59a2011-08-05 20:48:30 -07003447 menu.addMenuPresenter(listMenuPresenter);
3448 }
3449
3450 if (iconMenuPresenter != null) {
3451 listMenuPresenter.setItemIndexOffset(
3452 iconMenuPresenter.getNumActualItemsShown());
3453 }
3454 MenuView result = listMenuPresenter.getMenuView(decorView);
Adam Powell696cba52011-03-29 10:38:16 -07003455
Adam Powell696cba52011-03-29 10:38:16 -07003456 return result;
3457 }
3458
Adam Powell538e5652011-10-11 13:47:08 -07003459 MenuView getIconMenuView(Context context, MenuPresenter.Callback cb) {
Adam Powell696cba52011-03-29 10:38:16 -07003460 if (menu == null) return null;
3461
Adam Powell696cba52011-03-29 10:38:16 -07003462 if (iconMenuPresenter == null) {
Adam Powell538e5652011-10-11 13:47:08 -07003463 iconMenuPresenter = new IconMenuPresenter(context);
Adam Powell696cba52011-03-29 10:38:16 -07003464 iconMenuPresenter.setCallback(cb);
Alan Viverette40982d42014-07-25 17:48:55 -07003465 iconMenuPresenter.setId(R.id.icon_menu_presenter);
Adam Powell696cba52011-03-29 10:38:16 -07003466 menu.addMenuPresenter(iconMenuPresenter);
Adam Powell696cba52011-03-29 10:38:16 -07003467 }
3468
3469 MenuView result = iconMenuPresenter.getMenuView(decorView);
3470
Adam Powell696cba52011-03-29 10:38:16 -07003471 return result;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003472 }
3473
3474 Parcelable onSaveInstanceState() {
3475 SavedState savedState = new SavedState();
3476 savedState.featureId = featureId;
3477 savedState.isOpen = isOpen;
3478 savedState.isInExpandedMode = isInExpandedMode;
3479
3480 if (menu != null) {
3481 savedState.menuState = new Bundle();
Adam Powell11ed1d62011-07-11 21:19:59 -07003482 menu.savePresenterStates(savedState.menuState);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003483 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003484
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003485 return savedState;
3486 }
3487
3488 void onRestoreInstanceState(Parcelable state) {
3489 SavedState savedState = (SavedState) state;
3490 featureId = savedState.featureId;
Dianne Hackbornd0071442009-09-25 01:35:29 -07003491 wasLastOpen = savedState.isOpen;
3492 wasLastExpanded = savedState.isInExpandedMode;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003493 frozenMenuState = savedState.menuState;
3494
3495 /*
3496 * A LocalActivityManager keeps the same instance of this class around.
3497 * The first time the menu is being shown after restoring, the
3498 * Activity.onCreateOptionsMenu should be called. But, if it is the
3499 * same instance then menu != null and we won't call that method.
Adam Powell31bb97d2011-05-03 20:58:31 -07003500 * We clear any cached views here. The caller should invalidatePanelMenu.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003501 */
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003502 createdPanelView = null;
3503 shownPanelView = null;
3504 decorView = null;
3505 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003506
Adam Powell11ed1d62011-07-11 21:19:59 -07003507 void applyFrozenState() {
3508 if (menu != null && frozenMenuState != null) {
3509 menu.restorePresenterStates(frozenMenuState);
3510 frozenMenuState = null;
3511 }
3512 }
3513
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003514 private static class SavedState implements Parcelable {
3515 int featureId;
3516 boolean isOpen;
3517 boolean isInExpandedMode;
3518 Bundle menuState;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003519
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003520 public int describeContents() {
3521 return 0;
3522 }
3523
3524 public void writeToParcel(Parcel dest, int flags) {
3525 dest.writeInt(featureId);
3526 dest.writeInt(isOpen ? 1 : 0);
3527 dest.writeInt(isInExpandedMode ? 1 : 0);
3528
3529 if (isOpen) {
3530 dest.writeBundle(menuState);
3531 }
3532 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003533
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003534 private static SavedState readFromParcel(Parcel source) {
3535 SavedState savedState = new SavedState();
3536 savedState.featureId = source.readInt();
3537 savedState.isOpen = source.readInt() == 1;
3538 savedState.isInExpandedMode = source.readInt() == 1;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003539
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003540 if (savedState.isOpen) {
3541 savedState.menuState = source.readBundle();
3542 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003543
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003544 return savedState;
3545 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003546
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003547 public static final Parcelable.Creator<SavedState> CREATOR
3548 = new Parcelable.Creator<SavedState>() {
3549 public SavedState createFromParcel(Parcel in) {
3550 return readFromParcel(in);
3551 }
3552
3553 public SavedState[] newArray(int size) {
3554 return new SavedState[size];
3555 }
3556 };
3557 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003558
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003559 }
3560
Adam Powell6711f3b2015-05-06 15:57:09 -07003561 static class RotationWatcher extends Stub {
Adam Powelldfee59a2011-08-05 20:48:30 -07003562 private Handler mHandler;
3563 private final Runnable mRotationChanged = new Runnable() {
3564 public void run() {
3565 dispatchRotationChanged();
3566 }
3567 };
3568 private final ArrayList<WeakReference<PhoneWindow>> mWindows =
3569 new ArrayList<WeakReference<PhoneWindow>>();
3570 private boolean mIsWatching;
3571
3572 @Override
3573 public void onRotationChanged(int rotation) throws RemoteException {
3574 mHandler.post(mRotationChanged);
3575 }
3576
3577 public void addWindow(PhoneWindow phoneWindow) {
3578 synchronized (mWindows) {
3579 if (!mIsWatching) {
3580 try {
3581 WindowManagerHolder.sWindowManager.watchRotation(this);
3582 mHandler = new Handler();
3583 mIsWatching = true;
3584 } catch (RemoteException ex) {
3585 Log.e(TAG, "Couldn't start watching for device rotation", ex);
3586 }
3587 }
3588 mWindows.add(new WeakReference<PhoneWindow>(phoneWindow));
3589 }
3590 }
3591
3592 public void removeWindow(PhoneWindow phoneWindow) {
3593 synchronized (mWindows) {
3594 int i = 0;
3595 while (i < mWindows.size()) {
3596 final WeakReference<PhoneWindow> ref = mWindows.get(i);
3597 final PhoneWindow win = ref.get();
3598 if (win == null || win == phoneWindow) {
3599 mWindows.remove(i);
3600 } else {
3601 i++;
3602 }
3603 }
3604 }
3605 }
3606
3607 void dispatchRotationChanged() {
3608 synchronized (mWindows) {
3609 int i = 0;
3610 while (i < mWindows.size()) {
3611 final WeakReference<PhoneWindow> ref = mWindows.get(i);
3612 final PhoneWindow win = ref.get();
3613 if (win != null) {
3614 win.onOptionsPanelRotationChanged();
3615 i++;
3616 } else {
3617 mWindows.remove(i);
3618 }
3619 }
3620 }
3621 }
3622 }
3623
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003624 /**
3625 * Simple implementation of MenuBuilder.Callback that:
3626 * <li> Opens a submenu when selected.
3627 * <li> Calls back to the callback's onMenuItemSelected when an item is
3628 * selected.
3629 */
Alan Viverette77fb85e2015-12-14 11:42:44 -05003630 public static final class PhoneWindowMenuCallback
3631 implements MenuBuilder.Callback, MenuPresenter.Callback {
3632 private static final int FEATURE_ID = FEATURE_CONTEXT_MENU;
3633
3634 private final PhoneWindow mWindow;
3635
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003636 private MenuDialogHelper mSubMenuHelper;
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003637
Alan Viverette77fb85e2015-12-14 11:42:44 -05003638 private boolean mShowDialogForSubmenu;
3639
3640 public PhoneWindowMenuCallback(PhoneWindow window) {
3641 mWindow = window;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003642 }
3643
Alan Viverette77fb85e2015-12-14 11:42:44 -05003644 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003645 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
Adam Powelld1f42072011-05-03 17:20:14 -07003646 if (menu.getRootMenu() != menu) {
3647 onCloseSubMenu(menu);
3648 }
3649
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003650 if (allMenusAreClosing) {
Alan Viverette77fb85e2015-12-14 11:42:44 -05003651 final Callback callback = mWindow.getCallback();
3652 if (callback != null && !mWindow.isDestroyed()) {
3653 callback.onPanelClosed(FEATURE_ID, menu);
Dianne Hackbornb66ad572011-03-01 17:10:30 -08003654 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003655
Alan Viverette77fb85e2015-12-14 11:42:44 -05003656 if (menu == mWindow.mContextMenu) {
3657 mWindow.dismissContextMenu();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003658 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003659
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003660 // Dismiss the submenu, if it is showing
3661 if (mSubMenuHelper != null) {
3662 mSubMenuHelper.dismiss();
3663 mSubMenuHelper = null;
3664 }
3665 }
3666 }
3667
Alan Viverette77fb85e2015-12-14 11:42:44 -05003668 private void onCloseSubMenu(MenuBuilder menu) {
3669 final Callback callback = mWindow.getCallback();
3670 if (callback != null && !mWindow.isDestroyed()) {
3671 callback.onPanelClosed(FEATURE_ID, menu.getRootMenu());
Dianne Hackbornb66ad572011-03-01 17:10:30 -08003672 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003673 }
3674
Alan Viverette77fb85e2015-12-14 11:42:44 -05003675 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003676 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
Alan Viverette77fb85e2015-12-14 11:42:44 -05003677 final Callback callback = mWindow.getCallback();
3678 return callback != null && !mWindow.isDestroyed()
3679 && callback.onMenuItemSelected(FEATURE_ID, item);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003680 }
3681
Alan Viverette77fb85e2015-12-14 11:42:44 -05003682 @Override
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003683 public void onMenuModeChange(MenuBuilder menu) {
3684 }
3685
Alan Viverette77fb85e2015-12-14 11:42:44 -05003686 @Override
Adam Powelld1f42072011-05-03 17:20:14 -07003687 public boolean onOpenSubMenu(MenuBuilder subMenu) {
Alan Viverette77fb85e2015-12-14 11:42:44 -05003688 if (subMenu == null) {
3689 return false;
3690 }
Adam Powell823f0742011-09-21 17:17:01 -07003691
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003692 // Set a simple callback for the submenu
3693 subMenu.setCallback(this);
3694
Alan Viverette77fb85e2015-12-14 11:42:44 -05003695 if (mShowDialogForSubmenu) {
3696 // The window manager will give us a valid window token
3697 mSubMenuHelper = new MenuDialogHelper(subMenu);
3698 mSubMenuHelper.show(null);
3699 return true;
3700 }
The Android Open Source Projectbc8d29f2009-03-05 20:00:44 -08003701
Alan Viverette77fb85e2015-12-14 11:42:44 -05003702 return false;
3703 }
3704
3705 public void setShowDialogForSubmenu(boolean enabled) {
3706 mShowDialogForSubmenu = enabled;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003707 }
3708 }
3709
Wale Ogunwale8804af22015-11-17 09:18:15 -08003710 int getLocalFeaturesPrivate() {
3711 return super.getLocalFeatures();
3712 }
Adrian Roos05054bd2014-10-27 17:04:10 +01003713
Wale Ogunwale8804af22015-11-17 09:18:15 -08003714 protected void setDefaultWindowFormat(int format) {
3715 super.setDefaultWindowFormat(format);
Adrian Roos05054bd2014-10-27 17:04:10 +01003716 }
3717
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003718 void sendCloseSystemWindows() {
Jorim Jaggib10e33f2015-02-04 21:57:40 +01003719 sendCloseSystemWindows(getContext(), null);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003720 }
3721
3722 void sendCloseSystemWindows(String reason) {
Jorim Jaggib10e33f2015-02-04 21:57:40 +01003723 sendCloseSystemWindows(getContext(), reason);
3724 }
3725
3726 public static void sendCloseSystemWindows(Context context, String reason) {
3727 if (ActivityManagerNative.isSystemReady()) {
3728 try {
3729 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
3730 } catch (RemoteException e) {
3731 }
3732 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003733 }
Adrian Roos217ccd22014-05-09 14:29:04 +02003734
3735 @Override
3736 public int getStatusBarColor() {
Adrian Roos34e65442014-05-17 02:35:33 +02003737 return mStatusBarColor;
Adrian Roos217ccd22014-05-09 14:29:04 +02003738 }
3739
3740 @Override
3741 public void setStatusBarColor(int color) {
Adrian Roos34e65442014-05-17 02:35:33 +02003742 mStatusBarColor = color;
3743 mForcedStatusBarColor = true;
3744 if (mDecor != null) {
Adrian Roos05054bd2014-10-27 17:04:10 +01003745 mDecor.updateColorViews(null, false /* animate */);
Adrian Roos34e65442014-05-17 02:35:33 +02003746 }
Adrian Roos217ccd22014-05-09 14:29:04 +02003747 }
3748
3749 @Override
3750 public int getNavigationBarColor() {
Adrian Roos34e65442014-05-17 02:35:33 +02003751 return mNavigationBarColor;
Adrian Roos217ccd22014-05-09 14:29:04 +02003752 }
3753
3754 @Override
3755 public void setNavigationBarColor(int color) {
Adrian Roos34e65442014-05-17 02:35:33 +02003756 mNavigationBarColor = color;
3757 mForcedNavigationBarColor = true;
3758 if (mDecor != null) {
Adrian Roos05054bd2014-10-27 17:04:10 +01003759 mDecor.updateColorViews(null, false /* animate */);
Seigo Nonaka0a9d1ea2015-11-18 22:29:06 +09003760 mDecor.updateNavigationGuardColor();
Adrian Roos34e65442014-05-17 02:35:33 +02003761 }
Adrian Roos217ccd22014-05-09 14:29:04 +02003762 }
Jorim Jaggia16cc152015-06-01 16:55:05 -07003763
3764 public void setIsStartingWindow(boolean isStartingWindow) {
3765 mIsStartingWindow = isStartingWindow;
3766 }
Stefan Kuhnef4dd71a2015-08-07 09:28:52 -07003767
Filip Gruszczynskia59ac9c2015-09-10 18:28:48 -07003768 @Override
Filip Gruszczynski0daf2102015-09-29 08:39:07 -07003769 public void setTheme(int resid) {
3770 mTheme = resid;
3771 if (mDecor != null) {
3772 Context context = mDecor.getContext();
3773 if (context instanceof DecorContext) {
3774 context.setTheme(resid);
3775 }
3776 }
3777 }
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08003778
3779 @Override
3780 public void setResizingCaptionDrawable(Drawable drawable) {
3781 mDecor.setUserCaptionBackgroundDrawable(drawable);
3782 }
3783
3784 @Override
3785 public void setDecorCaptionShade(int decorCaptionShade) {
3786 mDecorCaptionShade = decorCaptionShade;
3787 if (mDecor != null) {
3788 mDecor.updateDecorCaptionShade();
3789 }
3790 }
3791
3792 int getDecorCaptionShade() {
3793 return mDecorCaptionShade;
3794 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003795
3796 @Override
3797 public void setAttributes(WindowManager.LayoutParams params) {
3798 super.setAttributes(params);
3799 if (mDecor != null) {
3800 mDecor.updateLogTag(params);
3801 }
3802 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08003803}