blob: 01709782fb91e2053aaad19e2b1e9b54931d6c6d [file] [log] [blame]
Wale Ogunwale8804af22015-11-17 09:18:15 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
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
17package com.android.internal.policy;
18
Robert Carr32bcb102018-01-29 15:03:23 -080019import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
Wale Ogunwale3382ab12017-07-27 08:55:03 -070020import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
21import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -080022import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
Jorim Jaggi8f5701b2016-04-04 18:36:02 -070023import static android.os.Build.VERSION_CODES.M;
24import static android.os.Build.VERSION_CODES.N;
Tiger Huang4a7835f2019-11-06 00:07:56 +080025import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
26import static android.view.InsetsState.ITYPE_STATUS_BAR;
Wale Ogunwale8804af22015-11-17 09:18:15 -080027import static android.view.View.MeasureSpec.AT_MOST;
28import static android.view.View.MeasureSpec.EXACTLY;
29import static android.view.View.MeasureSpec.getMode;
30import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
31import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
Filip Gruszczynski3dec0812015-12-09 08:42:41 -080032import static android.view.Window.DECOR_CAPTION_SHADE_DARK;
33import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT;
Wale Ogunwale8804af22015-11-17 09:18:15 -080034import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
35import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
Jorim Jaggi9f6798a2016-02-10 22:16:06 -080036import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
Jorim Jaggi65bff3e2016-02-08 19:17:07 -080037import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
Wale Ogunwale8804af22015-11-17 09:18:15 -080038import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
39import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
Wale Ogunwale0d7e9122015-11-17 10:45:06 -080040import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
41import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
Chong Zhangfea963e2016-08-15 17:14:16 -070042import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
Adrian Roos4c864592019-04-10 14:47:57 +020043
Clara Bayarri75e09792015-07-29 16:20:40 +010044import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
Wale Ogunwale8804af22015-11-17 09:18:15 -080045
John Reck32f140aa62018-10-04 15:08:24 -070046import android.animation.Animator;
47import android.animation.AnimatorListenerAdapter;
48import android.animation.ObjectAnimator;
49import android.annotation.Nullable;
50import android.annotation.TestApi;
51import android.app.WindowConfiguration;
Artur Satayeved5a6ae2019-12-10 17:47:54 +000052import android.compat.annotation.UnsupportedAppUsage;
John Reck32f140aa62018-10-04 15:08:24 -070053import android.content.Context;
54import android.content.res.Configuration;
55import android.content.res.Resources;
56import android.graphics.Canvas;
57import android.graphics.Color;
Jorim Jaggia6aabac2019-03-11 14:23:16 -070058import android.graphics.Insets;
John Reck32f140aa62018-10-04 15:08:24 -070059import android.graphics.LinearGradient;
60import android.graphics.Outline;
61import android.graphics.Paint;
62import android.graphics.PixelFormat;
63import android.graphics.RecordingCanvas;
64import android.graphics.Rect;
65import android.graphics.Region;
66import android.graphics.Shader;
67import android.graphics.drawable.ColorDrawable;
68import android.graphics.drawable.Drawable;
69import android.graphics.drawable.InsetDrawable;
70import android.graphics.drawable.LayerDrawable;
71import android.util.DisplayMetrics;
72import android.util.Log;
73import android.util.Pair;
74import android.util.TypedValue;
75import android.view.ActionMode;
76import android.view.ContextThemeWrapper;
77import android.view.Gravity;
78import android.view.InputQueue;
Tiger Huang4a7835f2019-11-06 00:07:56 +080079import android.view.InsetsState;
80import android.view.InsetsState.InternalInsetsType;
John Reck32f140aa62018-10-04 15:08:24 -070081import android.view.KeyEvent;
82import android.view.KeyboardShortcutGroup;
83import android.view.LayoutInflater;
84import android.view.Menu;
85import android.view.MenuItem;
86import android.view.MotionEvent;
87import android.view.ThreadedRenderer;
88import android.view.View;
89import android.view.ViewGroup;
90import android.view.ViewOutlineProvider;
Jorim Jaggi6482df52019-06-26 17:35:32 +020091import android.view.ViewRootImpl;
John Reck32f140aa62018-10-04 15:08:24 -070092import android.view.ViewStub;
93import android.view.ViewTreeObserver;
94import android.view.Window;
95import android.view.WindowCallbacks;
96import android.view.WindowInsets;
Tiger Huang4a7835f2019-11-06 00:07:56 +080097import android.view.WindowInsets.Side;
98import android.view.WindowInsets.Type;
99import android.view.WindowInsetsController;
John Reck32f140aa62018-10-04 15:08:24 -0700100import android.view.WindowManager;
101import android.view.accessibility.AccessibilityEvent;
102import android.view.accessibility.AccessibilityManager;
103import android.view.accessibility.AccessibilityNodeInfo;
104import android.view.animation.AnimationUtils;
105import android.view.animation.Interpolator;
106import android.widget.FrameLayout;
107import android.widget.PopupWindow;
108
109import com.android.internal.R;
110import com.android.internal.policy.PhoneWindow.PanelFeatureState;
111import com.android.internal.policy.PhoneWindow.PhoneWindowMenuCallback;
112import com.android.internal.view.FloatingActionMode;
113import com.android.internal.view.RootViewSurfaceTaker;
114import com.android.internal.view.StandaloneActionMode;
115import com.android.internal.view.menu.ContextMenuBuilder;
116import com.android.internal.view.menu.MenuHelper;
117import com.android.internal.widget.ActionBarContextView;
118import com.android.internal.widget.BackgroundFallback;
119import com.android.internal.widget.DecorCaptionView;
120import com.android.internal.widget.FloatingToolbar;
121
122import java.util.List;
123
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -0800124/** @hide */
125public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800126 private static final String TAG = "DecorView";
127
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -0800128 private static final boolean DEBUG_MEASURE = false;
129
Wale Ogunwale8804af22015-11-17 09:18:15 -0800130 private static final boolean SWEEP_OPEN_MENU = false;
131
Wale Ogunwale2b547c32015-11-18 10:33:22 -0800132 // The height of a window which has focus in DIP.
133 private final static int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20;
134 // The height of a window which has not in DIP.
135 private final static int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;
136
Adrian Roosc3f77562019-05-15 19:38:49 +0200137 private static final int SCRIM_LIGHT = 0xe6ffffff; // 90% white
Adrian Roos4c864592019-04-10 14:47:57 +0200138
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200139 public static final ColorViewAttributes STATUS_BAR_COLOR_VIEW_ATTRIBUTES =
140 new ColorViewAttributes(SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
141 Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
142 Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
143 com.android.internal.R.id.statusBarBackground,
Tiger Huang4a7835f2019-11-06 00:07:56 +0800144 FLAG_FULLSCREEN, ITYPE_STATUS_BAR);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200145
146 public static final ColorViewAttributes NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES =
147 new ColorViewAttributes(
148 SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
149 Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
150 Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
151 com.android.internal.R.id.navigationBarBackground,
Tiger Huang4a7835f2019-11-06 00:07:56 +0800152 0 /* hideWindowFlag */, ITYPE_NAVIGATION_BAR);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200153
Winson Chung4d8681f2017-05-23 16:22:08 -0700154 // This is used to workaround an issue where the PiP shadow can be transparent if the window
155 // background is transparent
156 private static final ViewOutlineProvider PIP_OUTLINE_PROVIDER = new ViewOutlineProvider() {
157 @Override
158 public void getOutline(View view, Outline outline) {
159 outline.setRect(0, 0, view.getWidth(), view.getHeight());
160 outline.setAlpha(1f);
161 }
162 };
163
Wale Ogunwale2b547c32015-11-18 10:33:22 -0800164 // Cludge to address b/22668382: Set the shadow size to the maximum so that the layer
165 // size calculation takes the shadow size into account. We set the elevation currently
166 // to max until the first layout command has been executed.
167 private boolean mAllowUpdateElevation = false;
168
169 private boolean mElevationAdjustedForStack = false;
170
Winson Chung4d8681f2017-05-23 16:22:08 -0700171 // Keeps track of the picture-in-picture mode for the view shadow
172 private boolean mIsInPictureInPictureMode;
173
174 // Stores the previous outline provider prior to applying PIP_OUTLINE_PROVIDER
175 private ViewOutlineProvider mLastOutlineProvider;
176
Wale Ogunwale8804af22015-11-17 09:18:15 -0800177 int mDefaultOpacity = PixelFormat.OPAQUE;
178
179 /** The feature ID of the panel, or -1 if this is the application's DecorView */
180 private final int mFeatureId;
181
182 private final Rect mDrawingBounds = new Rect();
183
184 private final Rect mBackgroundPadding = new Rect();
185
186 private final Rect mFramePadding = new Rect();
187
188 private final Rect mFrameOffsets = new Rect();
189
Wale Ogunwale62a91d62015-11-18 11:44:10 -0800190 private boolean mHasCaption = false;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800191
192 private boolean mChanging;
193
194 private Drawable mMenuBackground;
195 private boolean mWatchingForMenu;
196 private int mDownY;
197
198 ActionMode mPrimaryActionMode;
199 private ActionMode mFloatingActionMode;
200 private ActionBarContextView mPrimaryActionModeView;
201 private PopupWindow mPrimaryActionModePopup;
202 private Runnable mShowPrimaryActionModePopup;
203 private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener;
204 private View mFloatingActionModeOriginatingView;
205 private FloatingToolbar mFloatingToolbar;
206 private ObjectAnimator mFadeAnim;
207
208 // View added at runtime to draw under the status bar area
209 private View mStatusGuard;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800210
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200211 private final ColorViewState mStatusColorViewState =
212 new ColorViewState(STATUS_BAR_COLOR_VIEW_ATTRIBUTES);
213 private final ColorViewState mNavigationColorViewState =
214 new ColorViewState(NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800215
216 private final Interpolator mShowInterpolator;
217 private final Interpolator mHideInterpolator;
218 private final int mBarEnterExitDuration;
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700219 final boolean mForceWindowDrawsBarBackgrounds;
220 private final int mSemiTransparentBarColor;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800221
222 private final BackgroundFallback mBackgroundFallback = new BackgroundFallback();
223
224 private int mLastTopInset = 0;
Andrei Onea15884392019-03-22 17:28:11 +0000225 @UnsupportedAppUsage
Wale Ogunwale8804af22015-11-17 09:18:15 -0800226 private int mLastBottomInset = 0;
Andrei Onea15884392019-03-22 17:28:11 +0000227 @UnsupportedAppUsage
Wale Ogunwale8804af22015-11-17 09:18:15 -0800228 private int mLastRightInset = 0;
Andrei Onea15884392019-03-22 17:28:11 +0000229 @UnsupportedAppUsage
Adrian Roos85d202b2016-06-02 16:27:47 -0700230 private int mLastLeftInset = 0;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800231 private boolean mLastHasTopStableInset = false;
232 private boolean mLastHasBottomStableInset = false;
233 private boolean mLastHasRightStableInset = false;
Adrian Roos85d202b2016-06-02 16:27:47 -0700234 private boolean mLastHasLeftStableInset = false;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800235 private int mLastWindowFlags = 0;
Brad Stenninge0573692019-03-11 13:52:46 -0700236 private boolean mLastShouldAlwaysConsumeSystemBars = false;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800237
238 private int mRootScrollY = 0;
239
Andrei Onea15884392019-03-22 17:28:11 +0000240 @UnsupportedAppUsage
Wale Ogunwale8804af22015-11-17 09:18:15 -0800241 private PhoneWindow mWindow;
242
243 ViewGroup mContentRoot;
244
245 private Rect mTempRect;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800246
Wale Ogunwale62a91d62015-11-18 11:44:10 -0800247 // This is the caption view for the window, containing the caption and window control
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800248 // buttons. The visibility of this decor depends on the workspace and the window type.
249 // If the window type does not require such a view, this member might be null.
Garfield Tan3b9613c2018-12-26 17:08:51 -0800250 private DecorCaptionView mDecorCaptionView;
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800251
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -0800252 private boolean mWindowResizeCallbacksAdded = false;
Chong Zhangd3fd96c2016-02-08 18:25:24 -0800253 private Drawable.Callback mLastBackgroundDrawableCb = null;
Filip Gruszczynski3dec0812015-12-09 08:42:41 -0800254 private BackdropFrameRenderer mBackdropFrameRenderer = null;
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700255 private Drawable mOriginalBackgroundDrawable;
256 private Drawable mLastOriginalBackgroundDrawable;
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -0800257 private Drawable mResizingBackgroundDrawable;
Vadim Caen6932c772019-07-19 16:28:12 +0200258
259 /**
260 * Temporary holder for a window background when it is set before {@link #mWindow} is
261 * initialized. It will be set as the actual background once {@link #setWindow(PhoneWindow)} is
262 * called.
263 */
264 @Nullable
265 private Drawable mPendingWindowBackground;
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -0800266 private Drawable mCaptionBackgroundDrawable;
Filip Gruszczynski3dec0812015-12-09 08:42:41 -0800267 private Drawable mUserCaptionBackgroundDrawable;
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -0800268
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800269 private float mAvailableWidth;
270
271 String mLogTag = TAG;
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800272 private final Rect mFloatingInsets = new Rect();
273 private boolean mApplyFloatingVerticalInsets = false;
274 private boolean mApplyFloatingHorizontalInsets = false;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800275
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700276 private int mResizeMode = RESIZE_MODE_INVALID;
277 private final int mResizeShadowSize;
278 private final Paint mVerticalResizeShadowPaint = new Paint();
279 private final Paint mHorizontalResizeShadowPaint = new Paint();
Jorim Jaggi86d30ff2019-06-11 17:54:07 +0200280 private final Paint mLegacyNavigationBarBackgroundPaint = new Paint();
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700281 private Insets mBackgroundInsets = Insets.NONE;
282 private Insets mLastBackgroundInsets = Insets.NONE;
Jorim Jaggi86d30ff2019-06-11 17:54:07 +0200283 private boolean mDrawLegacyNavigationBarBackground;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700284
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800285 DecorView(Context context, int featureId, PhoneWindow window,
286 WindowManager.LayoutParams params) {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800287 super(context);
288 mFeatureId = featureId;
289
290 mShowInterpolator = AnimationUtils.loadInterpolator(context,
291 android.R.interpolator.linear_out_slow_in);
292 mHideInterpolator = AnimationUtils.loadInterpolator(context,
293 android.R.interpolator.fast_out_linear_in);
294
295 mBarEnterExitDuration = context.getResources().getInteger(
296 R.integer.dock_enter_exit_duration);
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700297 mForceWindowDrawsBarBackgrounds = context.getResources().getBoolean(
Jorim Jaggi8f5701b2016-04-04 18:36:02 -0700298 R.bool.config_forceWindowDrawsStatusBarBackground)
299 && context.getApplicationInfo().targetSdkVersion >= N;
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700300 mSemiTransparentBarColor = context.getResources().getColor(
Jorim Jaggi4fa78922015-11-30 17:13:56 -0800301 R.color.system_bar_background_semi_transparent, null /* theme */);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800302
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800303 updateAvailableWidth();
304
Wale Ogunwale8804af22015-11-17 09:18:15 -0800305 setWindow(window);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800306
307 updateLogTag(params);
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700308
309 mResizeShadowSize = context.getResources().getDimensionPixelSize(
310 R.dimen.resize_shadow_size);
311 initResizingPaints();
Jorim Jaggi86d30ff2019-06-11 17:54:07 +0200312
313 mLegacyNavigationBarBackgroundPaint.setColor(Color.BLACK);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800314 }
315
Nader Jawad56c68bc2018-04-24 17:08:51 -0700316 void setBackgroundFallback(@Nullable Drawable fallbackDrawable) {
317 mBackgroundFallback.setDrawable(fallbackDrawable);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800318 setWillNotDraw(getBackground() == null && !mBackgroundFallback.hasFallback());
319 }
320
Nader Jawad56c68bc2018-04-24 17:08:51 -0700321 @TestApi
322 public @Nullable Drawable getBackgroundFallback() {
323 return mBackgroundFallback.getDrawable();
324 }
325
Wale Ogunwale8804af22015-11-17 09:18:15 -0800326 @Override
Chris Craik867b8122016-05-05 16:19:22 -0700327 public boolean gatherTransparentRegion(Region region) {
328 boolean statusOpaque = gatherTransparentRegion(mStatusColorViewState, region);
329 boolean navOpaque = gatherTransparentRegion(mNavigationColorViewState, region);
330 boolean decorOpaque = super.gatherTransparentRegion(region);
331
332 // combine bools after computation, so each method above always executes
333 return statusOpaque || navOpaque || decorOpaque;
334 }
335
336 boolean gatherTransparentRegion(ColorViewState colorViewState, Region region) {
337 if (colorViewState.view != null && colorViewState.visible && isResizing()) {
338 // If a visible ColorViewState is in a resizing host DecorView, forcibly register its
339 // opaque area, since it's drawn by a different root RenderNode. It would otherwise be
340 // rejected by ViewGroup#gatherTransparentRegion() for the view not being VISIBLE.
341 return colorViewState.view.gatherTransparentRegion(region);
342 }
343 return false; // no opaque area added
344 }
345
346 @Override
Wale Ogunwale8804af22015-11-17 09:18:15 -0800347 public void onDraw(Canvas c) {
348 super.onDraw(c);
Jorim Jaggi853d17d2017-05-19 14:53:55 +0200349
Adrian Roos786ea782018-04-30 16:05:00 +0200350 mBackgroundFallback.draw(this, mContentRoot, c, mWindow.mContentParent,
351 mStatusColorViewState.view, mNavigationColorViewState.view);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800352 }
353
354 @Override
355 public boolean dispatchKeyEvent(KeyEvent event) {
356 final int keyCode = event.getKeyCode();
357 final int action = event.getAction();
358 final boolean isDown = action == KeyEvent.ACTION_DOWN;
359
360 if (isDown && (event.getRepeatCount() == 0)) {
361 // First handle chording of panel key: if a panel key is held
362 // but not released, try to execute a shortcut in it.
363 if ((mWindow.mPanelChordingKey > 0) && (mWindow.mPanelChordingKey != keyCode)) {
364 boolean handled = dispatchKeyShortcutEvent(event);
365 if (handled) {
366 return true;
367 }
368 }
369
370 // If a panel is open, perform a shortcut on it without the
371 // chorded panel key
372 if ((mWindow.mPreparedPanel != null) && mWindow.mPreparedPanel.isOpen) {
373 if (mWindow.performPanelShortcut(mWindow.mPreparedPanel, keyCode, event, 0)) {
374 return true;
375 }
376 }
377 }
378
379 if (!mWindow.isDestroyed()) {
380 final Window.Callback cb = mWindow.getCallback();
381 final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
382 : super.dispatchKeyEvent(event);
383 if (handled) {
384 return true;
385 }
386 }
387
388 return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event)
389 : mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
390 }
391
392 @Override
393 public boolean dispatchKeyShortcutEvent(KeyEvent ev) {
394 // If the panel is already prepared, then perform the shortcut using it.
395 boolean handled;
396 if (mWindow.mPreparedPanel != null) {
397 handled = mWindow.performPanelShortcut(mWindow.mPreparedPanel, ev.getKeyCode(), ev,
398 Menu.FLAG_PERFORM_NO_CLOSE);
399 if (handled) {
400 if (mWindow.mPreparedPanel != null) {
401 mWindow.mPreparedPanel.isHandled = true;
402 }
403 return true;
404 }
405 }
406
407 // Shortcut not handled by the panel. Dispatch to the view hierarchy.
408 final Window.Callback cb = mWindow.getCallback();
409 handled = cb != null && !mWindow.isDestroyed() && mFeatureId < 0
410 ? cb.dispatchKeyShortcutEvent(ev) : super.dispatchKeyShortcutEvent(ev);
411 if (handled) {
412 return true;
413 }
414
415 // If the panel is not prepared, then we may be trying to handle a shortcut key
416 // combination such as Control+C. Temporarily prepare the panel then mark it
417 // unprepared again when finished to ensure that the panel will again be prepared
418 // the next time it is shown for real.
419 PhoneWindow.PanelFeatureState st =
420 mWindow.getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
421 if (st != null && mWindow.mPreparedPanel == null) {
422 mWindow.preparePanel(st, ev);
423 handled = mWindow.performPanelShortcut(st, ev.getKeyCode(), ev,
424 Menu.FLAG_PERFORM_NO_CLOSE);
425 st.isPrepared = false;
426 if (handled) {
427 return true;
428 }
429 }
430 return false;
431 }
432
433 @Override
434 public boolean dispatchTouchEvent(MotionEvent ev) {
435 final Window.Callback cb = mWindow.getCallback();
436 return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
437 ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
438 }
439
440 @Override
441 public boolean dispatchTrackballEvent(MotionEvent ev) {
442 final Window.Callback cb = mWindow.getCallback();
443 return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
444 ? cb.dispatchTrackballEvent(ev) : super.dispatchTrackballEvent(ev);
445 }
446
447 @Override
448 public boolean dispatchGenericMotionEvent(MotionEvent ev) {
449 final Window.Callback cb = mWindow.getCallback();
450 return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
451 ? cb.dispatchGenericMotionEvent(ev) : super.dispatchGenericMotionEvent(ev);
452 }
453
454 public boolean superDispatchKeyEvent(KeyEvent event) {
455 // Give priority to closing action modes if applicable.
456 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
457 final int action = event.getAction();
458 // Back cancels action modes first.
459 if (mPrimaryActionMode != null) {
460 if (action == KeyEvent.ACTION_UP) {
461 mPrimaryActionMode.finish();
462 }
463 return true;
464 }
465 }
466
Evan Rosky5e29c072017-06-02 17:31:22 -0700467 if (super.dispatchKeyEvent(event)) {
468 return true;
469 }
470
Evan Roskycd80e612018-05-17 17:46:09 -0700471 return (getViewRootImpl() != null) && getViewRootImpl().dispatchUnhandledKeyEvent(event);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800472 }
473
474 public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
475 return super.dispatchKeyShortcutEvent(event);
476 }
477
478 public boolean superDispatchTouchEvent(MotionEvent event) {
479 return super.dispatchTouchEvent(event);
480 }
481
482 public boolean superDispatchTrackballEvent(MotionEvent event) {
483 return super.dispatchTrackballEvent(event);
484 }
485
486 public boolean superDispatchGenericMotionEvent(MotionEvent event) {
487 return super.dispatchGenericMotionEvent(event);
488 }
489
490 @Override
491 public boolean onTouchEvent(MotionEvent event) {
492 return onInterceptTouchEvent(event);
493 }
494
495 private boolean isOutOfInnerBounds(int x, int y) {
496 return x < 0 || y < 0 || x > getWidth() || y > getHeight();
497 }
498
499 private boolean isOutOfBounds(int x, int y) {
500 return x < -5 || y < -5 || x > (getWidth() + 5)
501 || y > (getHeight() + 5);
502 }
503
504 @Override
505 public boolean onInterceptTouchEvent(MotionEvent event) {
506 int action = event.getAction();
Wale Ogunwale62a91d62015-11-18 11:44:10 -0800507 if (mHasCaption && isShowingCaption()) {
508 // Don't dispatch ACTION_DOWN to the captionr if the window is resizable and the event
509 // was (starting) outside the window. Window resizing events should be handled by
510 // WindowManager.
Wale Ogunwale8804af22015-11-17 09:18:15 -0800511 // TODO: Investigate how to handle the outside touch in window manager
512 // without generating these events.
513 // Currently we receive these because we need to enlarge the window's
514 // touch region so that the monitor channel receives the events
515 // in the outside touch area.
516 if (action == MotionEvent.ACTION_DOWN) {
517 final int x = (int) event.getX();
518 final int y = (int) event.getY();
519 if (isOutOfInnerBounds(x, y)) {
520 return true;
521 }
522 }
523 }
524
525 if (mFeatureId >= 0) {
526 if (action == MotionEvent.ACTION_DOWN) {
527 int x = (int)event.getX();
528 int y = (int)event.getY();
529 if (isOutOfBounds(x, y)) {
530 mWindow.closePanel(mFeatureId);
531 return true;
532 }
533 }
534 }
535
536 if (!SWEEP_OPEN_MENU) {
537 return false;
538 }
539
540 if (mFeatureId >= 0) {
541 if (action == MotionEvent.ACTION_DOWN) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800542 Log.i(mLogTag, "Watchiing!");
Wale Ogunwale8804af22015-11-17 09:18:15 -0800543 mWatchingForMenu = true;
544 mDownY = (int) event.getY();
545 return false;
546 }
547
548 if (!mWatchingForMenu) {
549 return false;
550 }
551
552 int y = (int)event.getY();
553 if (action == MotionEvent.ACTION_MOVE) {
554 if (y > (mDownY+30)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800555 Log.i(mLogTag, "Closing!");
Wale Ogunwale8804af22015-11-17 09:18:15 -0800556 mWindow.closePanel(mFeatureId);
557 mWatchingForMenu = false;
558 return true;
559 }
560 } else if (action == MotionEvent.ACTION_UP) {
561 mWatchingForMenu = false;
562 }
563
564 return false;
565 }
566
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800567 //Log.i(mLogTag, "Intercept: action=" + action + " y=" + event.getY()
Wale Ogunwale8804af22015-11-17 09:18:15 -0800568 // + " (in " + getHeight() + ")");
569
570 if (action == MotionEvent.ACTION_DOWN) {
571 int y = (int)event.getY();
572 if (y >= (getHeight()-5) && !mWindow.hasChildren()) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800573 Log.i(mLogTag, "Watching!");
Wale Ogunwale8804af22015-11-17 09:18:15 -0800574 mWatchingForMenu = true;
575 }
576 return false;
577 }
578
579 if (!mWatchingForMenu) {
580 return false;
581 }
582
583 int y = (int)event.getY();
584 if (action == MotionEvent.ACTION_MOVE) {
585 if (y < (getHeight()-30)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800586 Log.i(mLogTag, "Opening!");
Wale Ogunwale8804af22015-11-17 09:18:15 -0800587 mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, new KeyEvent(
588 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
589 mWatchingForMenu = false;
590 return true;
591 }
592 } else if (action == MotionEvent.ACTION_UP) {
593 mWatchingForMenu = false;
594 }
595
596 return false;
597 }
598
599 @Override
600 public void sendAccessibilityEvent(int eventType) {
601 if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
602 return;
603 }
604
605 // if we are showing a feature that should be announced and one child
606 // make this child the event source since this is the feature itself
607 // otherwise the callback will take over and announce its client
608 if ((mFeatureId == Window.FEATURE_OPTIONS_PANEL ||
609 mFeatureId == Window.FEATURE_CONTEXT_MENU ||
610 mFeatureId == Window.FEATURE_PROGRESS ||
611 mFeatureId == Window.FEATURE_INDETERMINATE_PROGRESS)
612 && getChildCount() == 1) {
613 getChildAt(0).sendAccessibilityEvent(eventType);
614 } else {
615 super.sendAccessibilityEvent(eventType);
616 }
617 }
618
619 @Override
620 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
621 final Window.Callback cb = mWindow.getCallback();
622 if (cb != null && !mWindow.isDestroyed()) {
623 if (cb.dispatchPopulateAccessibilityEvent(event)) {
624 return true;
625 }
626 }
627 return super.dispatchPopulateAccessibilityEventInternal(event);
628 }
629
630 @Override
631 protected boolean setFrame(int l, int t, int r, int b) {
632 boolean changed = super.setFrame(l, t, r, b);
633 if (changed) {
634 final Rect drawingBounds = mDrawingBounds;
635 getDrawingRect(drawingBounds);
636
637 Drawable fg = getForeground();
638 if (fg != null) {
639 final Rect frameOffsets = mFrameOffsets;
640 drawingBounds.left += frameOffsets.left;
641 drawingBounds.top += frameOffsets.top;
642 drawingBounds.right -= frameOffsets.right;
643 drawingBounds.bottom -= frameOffsets.bottom;
644 fg.setBounds(drawingBounds);
645 final Rect framePadding = mFramePadding;
646 drawingBounds.left += framePadding.left - frameOffsets.left;
647 drawingBounds.top += framePadding.top - frameOffsets.top;
648 drawingBounds.right -= framePadding.right - frameOffsets.right;
649 drawingBounds.bottom -= framePadding.bottom - frameOffsets.bottom;
650 }
651
Jorim Jaggi24cf50f2019-04-09 15:16:23 +0200652 // Need to call super here as we pretend to be having the original background.
653 Drawable bg = super.getBackground();
Wale Ogunwale8804af22015-11-17 09:18:15 -0800654 if (bg != null) {
655 bg.setBounds(drawingBounds);
656 }
657
658 if (SWEEP_OPEN_MENU) {
659 if (mMenuBackground == null && mFeatureId < 0
660 && mWindow.getAttributes().height
661 == WindowManager.LayoutParams.MATCH_PARENT) {
662 mMenuBackground = getContext().getDrawable(
663 R.drawable.menu_background);
664 }
665 if (mMenuBackground != null) {
666 mMenuBackground.setBounds(drawingBounds.left,
667 drawingBounds.bottom-6, drawingBounds.right,
668 drawingBounds.bottom+20);
669 }
670 }
671 }
672 return changed;
673 }
674
675 @Override
676 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
677 final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800678 final boolean isPortrait =
679 getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800680
681 final int widthMode = getMode(widthMeasureSpec);
682 final int heightMode = getMode(heightMeasureSpec);
683
684 boolean fixedWidth = false;
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800685 mApplyFloatingHorizontalInsets = false;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800686 if (widthMode == AT_MOST) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800687 final TypedValue tvw = isPortrait ? mWindow.mFixedWidthMinor : mWindow.mFixedWidthMajor;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800688 if (tvw != null && tvw.type != TypedValue.TYPE_NULL) {
689 final int w;
690 if (tvw.type == TypedValue.TYPE_DIMENSION) {
691 w = (int) tvw.getDimension(metrics);
692 } else if (tvw.type == TypedValue.TYPE_FRACTION) {
693 w = (int) tvw.getFraction(metrics.widthPixels, metrics.widthPixels);
694 } else {
695 w = 0;
696 }
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -0800697 if (DEBUG_MEASURE) Log.d(mLogTag, "Fixed width: " + w);
Jorim Jaggiffd04902016-02-23 19:20:59 -0500698 final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800699 if (w > 0) {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800700 widthMeasureSpec = MeasureSpec.makeMeasureSpec(
701 Math.min(w, widthSize), EXACTLY);
702 fixedWidth = true;
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800703 } else {
704 widthMeasureSpec = MeasureSpec.makeMeasureSpec(
Jorim Jaggiffd04902016-02-23 19:20:59 -0500705 widthSize - mFloatingInsets.left - mFloatingInsets.right,
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800706 AT_MOST);
707 mApplyFloatingHorizontalInsets = true;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800708 }
709 }
710 }
711
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800712 mApplyFloatingVerticalInsets = false;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800713 if (heightMode == AT_MOST) {
714 final TypedValue tvh = isPortrait ? mWindow.mFixedHeightMajor
715 : mWindow.mFixedHeightMinor;
716 if (tvh != null && tvh.type != TypedValue.TYPE_NULL) {
717 final int h;
718 if (tvh.type == TypedValue.TYPE_DIMENSION) {
719 h = (int) tvh.getDimension(metrics);
720 } else if (tvh.type == TypedValue.TYPE_FRACTION) {
721 h = (int) tvh.getFraction(metrics.heightPixels, metrics.heightPixels);
722 } else {
723 h = 0;
724 }
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -0800725 if (DEBUG_MEASURE) Log.d(mLogTag, "Fixed height: " + h);
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800726 final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800727 if (h > 0) {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800728 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
729 Math.min(h, heightSize), EXACTLY);
Jorim Jaggi65bff3e2016-02-08 19:17:07 -0800730 } else if ((mWindow.getAttributes().flags & FLAG_LAYOUT_IN_SCREEN) == 0) {
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800731 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
732 heightSize - mFloatingInsets.top - mFloatingInsets.bottom, AT_MOST);
733 mApplyFloatingVerticalInsets = true;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800734 }
735 }
736 }
737
Wale Ogunwale8804af22015-11-17 09:18:15 -0800738 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
739
740 int width = getMeasuredWidth();
741 boolean measure = false;
742
743 widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
744
745 if (!fixedWidth && widthMode == AT_MOST) {
746 final TypedValue tv = isPortrait ? mWindow.mMinWidthMinor : mWindow.mMinWidthMajor;
747 if (tv.type != TypedValue.TYPE_NULL) {
748 final int min;
749 if (tv.type == TypedValue.TYPE_DIMENSION) {
750 min = (int)tv.getDimension(metrics);
751 } else if (tv.type == TypedValue.TYPE_FRACTION) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800752 min = (int)tv.getFraction(mAvailableWidth, mAvailableWidth);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800753 } else {
754 min = 0;
755 }
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -0800756 if (DEBUG_MEASURE) Log.d(mLogTag, "Adjust for min width: " + min + ", value::"
757 + tv.coerceToString() + ", mAvailableWidth=" + mAvailableWidth);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800758
759 if (width < min) {
760 widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
761 measure = true;
762 }
763 }
764 }
765
766 // TODO: Support height?
767
768 if (measure) {
769 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
770 }
771 }
772
773 @Override
774 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
775 super.onLayout(changed, left, top, right, bottom);
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800776 if (mApplyFloatingVerticalInsets) {
777 offsetTopAndBottom(mFloatingInsets.top);
778 }
779 if (mApplyFloatingHorizontalInsets) {
780 offsetLeftAndRight(mFloatingInsets.left);
781 }
Wale Ogunwale2b547c32015-11-18 10:33:22 -0800782
783 // If the application changed its SystemUI metrics, we might also have to adapt
784 // our shadow elevation.
785 updateElevation();
786 mAllowUpdateElevation = true;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700787
Vinit Nayak7ab1fb82019-09-12 18:15:21 -0700788 if (changed
789 && (mResizeMode == RESIZE_MODE_DOCKED_DIVIDER
790 || mDrawLegacyNavigationBarBackground)) {
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700791 getViewRootImpl().requestInvalidateRootRenderNode();
792 }
Wale Ogunwale8804af22015-11-17 09:18:15 -0800793 }
794
795 @Override
796 public void draw(Canvas canvas) {
797 super.draw(canvas);
798
799 if (mMenuBackground != null) {
800 mMenuBackground.draw(canvas);
801 }
802 }
803
804 @Override
805 public boolean showContextMenuForChild(View originalView) {
Oren Blasberg23e282d2016-04-20 13:43:45 -0700806 return showContextMenuForChildInternal(originalView, Float.NaN, Float.NaN);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800807 }
808
809 @Override
810 public boolean showContextMenuForChild(View originalView, float x, float y) {
Oren Blasberg23e282d2016-04-20 13:43:45 -0700811 return showContextMenuForChildInternal(originalView, x, y);
Alan Viverette021627e2015-11-25 14:22:00 -0500812 }
813
814 private boolean showContextMenuForChildInternal(View originalView,
Oren Blasberg23e282d2016-04-20 13:43:45 -0700815 float x, float y) {
Alan Viverette021627e2015-11-25 14:22:00 -0500816 // Only allow one context menu at a time.
817 if (mWindow.mContextMenuHelper != null) {
818 mWindow.mContextMenuHelper.dismiss();
819 mWindow.mContextMenuHelper = null;
820 }
821
822 // Reuse the context menu builder.
Alan Viverette77fb85e2015-12-14 11:42:44 -0500823 final PhoneWindowMenuCallback callback = mWindow.mContextMenuCallback;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800824 if (mWindow.mContextMenu == null) {
825 mWindow.mContextMenu = new ContextMenuBuilder(getContext());
Alan Viverette77fb85e2015-12-14 11:42:44 -0500826 mWindow.mContextMenu.setCallback(callback);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800827 } else {
828 mWindow.mContextMenu.clearAll();
829 }
830
Alan Viverette021627e2015-11-25 14:22:00 -0500831 final MenuHelper helper;
Oren Blasberg23e282d2016-04-20 13:43:45 -0700832 final boolean isPopup = !Float.isNaN(x) && !Float.isNaN(y);
Alan Viverette021627e2015-11-25 14:22:00 -0500833 if (isPopup) {
834 helper = mWindow.mContextMenu.showPopup(getContext(), originalView, x, y);
835 } else {
836 helper = mWindow.mContextMenu.showDialog(originalView, originalView.getWindowToken());
Wale Ogunwale8804af22015-11-17 09:18:15 -0800837 }
Alan Viverette021627e2015-11-25 14:22:00 -0500838
Alan Viverette9084d222015-12-16 09:56:37 -0500839 if (helper != null) {
840 // If it's a dialog, the callback needs to handle showing
841 // sub-menus. Either way, the callback is required for propagating
842 // selection to Context.onContextMenuItemSelected().
843 callback.setShowDialogForSubmenu(!isPopup);
844 helper.setPresenterCallback(callback);
845 }
Alan Viverette021627e2015-11-25 14:22:00 -0500846
847 mWindow.mContextMenuHelper = helper;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800848 return helper != null;
849 }
850
851 @Override
852 public ActionMode startActionModeForChild(View originalView,
853 ActionMode.Callback callback) {
854 return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
855 }
856
857 @Override
858 public ActionMode startActionModeForChild(
859 View child, ActionMode.Callback callback, int type) {
860 return startActionMode(child, callback, type);
861 }
862
863 @Override
864 public ActionMode startActionMode(ActionMode.Callback callback) {
865 return startActionMode(callback, ActionMode.TYPE_PRIMARY);
866 }
867
868 @Override
869 public ActionMode startActionMode(ActionMode.Callback callback, int type) {
870 return startActionMode(this, callback, type);
871 }
872
873 private ActionMode startActionMode(
874 View originatingView, ActionMode.Callback callback, int type) {
875 ActionMode.Callback2 wrappedCallback = new ActionModeCallback2Wrapper(callback);
876 ActionMode mode = null;
877 if (mWindow.getCallback() != null && !mWindow.isDestroyed()) {
878 try {
879 mode = mWindow.getCallback().onWindowStartingActionMode(wrappedCallback, type);
880 } catch (AbstractMethodError ame) {
881 // Older apps might not implement the typed version of this method.
882 if (type == ActionMode.TYPE_PRIMARY) {
883 try {
884 mode = mWindow.getCallback().onWindowStartingActionMode(
885 wrappedCallback);
886 } catch (AbstractMethodError ame2) {
887 // Older apps might not implement this callback method at all.
888 }
889 }
890 }
891 }
892 if (mode != null) {
893 if (mode.getType() == ActionMode.TYPE_PRIMARY) {
894 cleanupPrimaryActionMode();
895 mPrimaryActionMode = mode;
896 } else if (mode.getType() == ActionMode.TYPE_FLOATING) {
897 if (mFloatingActionMode != null) {
898 mFloatingActionMode.finish();
899 }
900 mFloatingActionMode = mode;
901 }
902 } else {
903 mode = createActionMode(type, wrappedCallback, originatingView);
904 if (mode != null && wrappedCallback.onCreateActionMode(mode, mode.getMenu())) {
905 setHandledActionMode(mode);
906 } else {
907 mode = null;
908 }
909 }
910 if (mode != null && mWindow.getCallback() != null && !mWindow.isDestroyed()) {
911 try {
912 mWindow.getCallback().onActionModeStarted(mode);
913 } catch (AbstractMethodError ame) {
914 // Older apps might not implement this callback method.
915 }
916 }
917 return mode;
918 }
919
920 private void cleanupPrimaryActionMode() {
921 if (mPrimaryActionMode != null) {
922 mPrimaryActionMode.finish();
923 mPrimaryActionMode = null;
924 }
925 if (mPrimaryActionModeView != null) {
926 mPrimaryActionModeView.killMode();
927 }
928 }
929
930 private void cleanupFloatingActionModeViews() {
931 if (mFloatingToolbar != null) {
932 mFloatingToolbar.dismiss();
933 mFloatingToolbar = null;
934 }
935 if (mFloatingActionModeOriginatingView != null) {
936 if (mFloatingToolbarPreDrawListener != null) {
937 mFloatingActionModeOriginatingView.getViewTreeObserver()
938 .removeOnPreDrawListener(mFloatingToolbarPreDrawListener);
939 mFloatingToolbarPreDrawListener = null;
940 }
941 mFloatingActionModeOriginatingView = null;
942 }
943 }
944
Wale Ogunwale62a91d62015-11-18 11:44:10 -0800945 void startChanging() {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800946 mChanging = true;
947 }
948
Wale Ogunwale62a91d62015-11-18 11:44:10 -0800949 void finishChanging() {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800950 mChanging = false;
951 drawableChanged();
952 }
953
954 public void setWindowBackground(Drawable drawable) {
Vadim Caen6932c772019-07-19 16:28:12 +0200955 if (mWindow == null) {
956 mPendingWindowBackground = drawable;
957 return;
958 }
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700959 if (mOriginalBackgroundDrawable != drawable) {
960 mOriginalBackgroundDrawable = drawable;
961 updateBackgroundDrawable();
Wale Ogunwale8804af22015-11-17 09:18:15 -0800962 if (drawable != null) {
Jorim Jaggi8e879f12016-05-25 16:41:49 -0700963 mResizingBackgroundDrawable = enforceNonTranslucentBackground(drawable,
964 mWindow.isTranslucent() || mWindow.isShowingWallpaper());
Robert Carr692a5fe2016-05-19 14:11:15 -0700965 } else {
966 mResizingBackgroundDrawable = getResizingBackgroundDrawable(
Nader Jawad56c68bc2018-04-24 17:08:51 -0700967 mWindow.mBackgroundDrawable, mWindow.mBackgroundFallbackDrawable,
Jorim Jaggi8e879f12016-05-25 16:41:49 -0700968 mWindow.isTranslucent() || mWindow.isShowingWallpaper());
Robert Carr692a5fe2016-05-19 14:11:15 -0700969 }
970 if (mResizingBackgroundDrawable != null) {
971 mResizingBackgroundDrawable.getPadding(mBackgroundPadding);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800972 } else {
973 mBackgroundPadding.setEmpty();
974 }
Vadim Caenef4e1ce2019-07-25 14:53:56 +0200975 if (!View.sBrokenWindowBackground) {
976 drawableChanged();
977 }
Wale Ogunwale8804af22015-11-17 09:18:15 -0800978 }
979 }
980
Jorim Jaggi24cf50f2019-04-09 15:16:23 +0200981 @Override
982 public void setBackgroundDrawable(Drawable background) {
Vadim Caene664c702019-07-09 14:26:00 +0200983 setWindowBackground(background);
Jorim Jaggi24cf50f2019-04-09 15:16:23 +0200984 }
985
Wale Ogunwale8804af22015-11-17 09:18:15 -0800986 public void setWindowFrame(Drawable drawable) {
987 if (getForeground() != drawable) {
988 setForeground(drawable);
989 if (drawable != null) {
990 drawable.getPadding(mFramePadding);
991 } else {
992 mFramePadding.setEmpty();
993 }
994 drawableChanged();
995 }
996 }
997
998 @Override
999 public void onWindowSystemUiVisibilityChanged(int visible) {
1000 updateColorViews(null /* insets */, true /* animate */);
Garfield Tan3b9613c2018-12-26 17:08:51 -08001001 updateDecorCaptionStatus(getResources().getConfiguration());
Adrian Roos27db0ca2019-05-29 16:12:09 +02001002
1003 if (mStatusGuard != null && mStatusGuard.getVisibility() == VISIBLE) {
1004 updateStatusGuardColor();
1005 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001006 }
1007
1008 @Override
1009 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -08001010 final WindowManager.LayoutParams attrs = mWindow.getAttributes();
1011 mFloatingInsets.setEmpty();
Jorim Jaggi65bff3e2016-02-08 19:17:07 -08001012 if ((attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0) {
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -08001013 // For dialog windows we want to make sure they don't go over the status bar or nav bar.
1014 // We consume the system insets and we will reuse them later during the measure phase.
Jorim Jaggi65bff3e2016-02-08 19:17:07 -08001015 // We allow the app to ignore this and handle insets itself by using
1016 // FLAG_LAYOUT_IN_SCREEN.
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -08001017 if (attrs.height == WindowManager.LayoutParams.WRAP_CONTENT) {
1018 mFloatingInsets.top = insets.getSystemWindowInsetTop();
1019 mFloatingInsets.bottom = insets.getSystemWindowInsetBottom();
Adrian Roosf7b74262017-11-22 14:21:01 +01001020 insets = insets.inset(0, insets.getSystemWindowInsetTop(),
1021 0, insets.getSystemWindowInsetBottom());
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -08001022 }
1023 if (mWindow.getAttributes().width == WindowManager.LayoutParams.WRAP_CONTENT) {
1024 mFloatingInsets.left = insets.getSystemWindowInsetTop();
1025 mFloatingInsets.right = insets.getSystemWindowInsetBottom();
Adrian Roosf7b74262017-11-22 14:21:01 +01001026 insets = insets.inset(insets.getSystemWindowInsetLeft(), 0,
1027 insets.getSystemWindowInsetRight(), 0);
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -08001028 }
1029 }
Adrian Roos60f59292018-08-24 16:29:06 +02001030 mFrameOffsets.set(insets.getSystemWindowInsetsAsRect());
Wale Ogunwale8804af22015-11-17 09:18:15 -08001031 insets = updateColorViews(insets, true /* animate */);
1032 insets = updateStatusGuard(insets);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001033 if (getForeground() != null) {
1034 drawableChanged();
1035 }
1036 return insets;
1037 }
1038
1039 @Override
1040 public boolean isTransitionGroup() {
1041 return false;
1042 }
1043
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001044 public static int getColorViewTopInset(int stableTop, int systemTop) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001045 return Math.min(stableTop, systemTop);
1046 }
1047
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001048 public static int getColorViewBottomInset(int stableBottom, int systemBottom) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001049 return Math.min(stableBottom, systemBottom);
1050 }
1051
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001052 public static int getColorViewRightInset(int stableRight, int systemRight) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001053 return Math.min(stableRight, systemRight);
1054 }
1055
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001056 public static int getColorViewLeftInset(int stableLeft, int systemLeft) {
Adrian Roos85d202b2016-06-02 16:27:47 -07001057 return Math.min(stableLeft, systemLeft);
1058 }
1059
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001060 public static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001061 return bottomInset == 0 && rightInset > 0;
1062 }
1063
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001064 public static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
Adrian Roos85d202b2016-06-02 16:27:47 -07001065 return bottomInset == 0 && leftInset > 0;
1066 }
1067
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001068 public static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
Adrian Roos85d202b2016-06-02 16:27:47 -07001069 return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset
1070 : isNavBarToLeftEdge(bottomInset, leftInset) ? leftInset : bottomInset;
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001071 }
1072
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001073 public static void getNavigationBarRect(int canvasWidth, int canvasHeight, Rect stableInsets,
Winson Chungffde2ea2019-06-17 17:19:13 -07001074 Rect contentInsets, Rect outRect, float scale) {
1075 final int bottomInset =
1076 (int) (getColorViewBottomInset(stableInsets.bottom, contentInsets.bottom) * scale);
1077 final int leftInset =
1078 (int) (getColorViewLeftInset(stableInsets.left, contentInsets.left) * scale);
1079 final int rightInset =
1080 (int) (getColorViewLeftInset(stableInsets.right, contentInsets.right) * scale);
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001081 final int size = getNavBarSize(bottomInset, rightInset, leftInset);
1082 if (isNavBarToRightEdge(bottomInset, rightInset)) {
1083 outRect.set(canvasWidth - size, 0, canvasWidth, canvasHeight);
1084 } else if (isNavBarToLeftEdge(bottomInset, leftInset)) {
1085 outRect.set(0, 0, size, canvasHeight);
1086 } else {
1087 outRect.set(0, canvasHeight - size, canvasWidth, canvasHeight);
1088 }
1089 }
1090
Wale Ogunwale8804af22015-11-17 09:18:15 -08001091 WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
1092 WindowManager.LayoutParams attrs = mWindow.getAttributes();
1093 int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
1094
Tiger Huang4a7835f2019-11-06 00:07:56 +08001095 final WindowInsetsController controller = getWindowInsetsController();
1096 final InsetsState state = controller != null ? controller.getState() : null;
1097
Yohei Yukawa8f162c62018-01-10 13:18:09 -08001098 // IME is an exceptional floating window that requires color view.
1099 final boolean isImeWindow =
1100 mWindow.getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD;
1101 if (!mWindow.mIsFloating || isImeWindow) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001102 boolean disallowAnimate = !isLaidOut();
1103 disallowAnimate |= ((mLastWindowFlags ^ attrs.flags)
1104 & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
1105 mLastWindowFlags = attrs.flags;
1106
1107 if (insets != null) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001108 mLastTopInset = getColorViewTopInset(insets.getStableInsetTop(),
Wale Ogunwale8804af22015-11-17 09:18:15 -08001109 insets.getSystemWindowInsetTop());
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001110 mLastBottomInset = getColorViewBottomInset(insets.getStableInsetBottom(),
Wale Ogunwale8804af22015-11-17 09:18:15 -08001111 insets.getSystemWindowInsetBottom());
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001112 mLastRightInset = getColorViewRightInset(insets.getStableInsetRight(),
Wale Ogunwale8804af22015-11-17 09:18:15 -08001113 insets.getSystemWindowInsetRight());
Adrian Roos85d202b2016-06-02 16:27:47 -07001114 mLastLeftInset = getColorViewRightInset(insets.getStableInsetLeft(),
1115 insets.getSystemWindowInsetLeft());
Wale Ogunwale8804af22015-11-17 09:18:15 -08001116
1117 // Don't animate if the presence of stable insets has changed, because that
1118 // indicates that the window was either just added and received them for the
1119 // first time, or the window size or position has changed.
1120 boolean hasTopStableInset = insets.getStableInsetTop() != 0;
1121 disallowAnimate |= (hasTopStableInset != mLastHasTopStableInset);
1122 mLastHasTopStableInset = hasTopStableInset;
1123
1124 boolean hasBottomStableInset = insets.getStableInsetBottom() != 0;
1125 disallowAnimate |= (hasBottomStableInset != mLastHasBottomStableInset);
1126 mLastHasBottomStableInset = hasBottomStableInset;
1127
1128 boolean hasRightStableInset = insets.getStableInsetRight() != 0;
1129 disallowAnimate |= (hasRightStableInset != mLastHasRightStableInset);
1130 mLastHasRightStableInset = hasRightStableInset;
Adrian Roos85d202b2016-06-02 16:27:47 -07001131
1132 boolean hasLeftStableInset = insets.getStableInsetLeft() != 0;
1133 disallowAnimate |= (hasLeftStableInset != mLastHasLeftStableInset);
1134 mLastHasLeftStableInset = hasLeftStableInset;
1135
Brad Stenninge0573692019-03-11 13:52:46 -07001136 mLastShouldAlwaysConsumeSystemBars = insets.shouldAlwaysConsumeSystemBars();
Wale Ogunwale8804af22015-11-17 09:18:15 -08001137 }
1138
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001139 boolean navBarToRightEdge = isNavBarToRightEdge(mLastBottomInset, mLastRightInset);
Adrian Roos85d202b2016-06-02 16:27:47 -07001140 boolean navBarToLeftEdge = isNavBarToLeftEdge(mLastBottomInset, mLastLeftInset);
1141 int navBarSize = getNavBarSize(mLastBottomInset, mLastRightInset, mLastLeftInset);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001142 updateColorViewInt(mNavigationColorViewState, sysUiVisibility,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001143 calculateNavigationBarColor(), mWindow.mNavigationBarDividerColor, navBarSize,
Jason Monkea506c62017-09-01 12:40:06 -04001144 navBarToRightEdge || navBarToLeftEdge, navBarToLeftEdge,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001145 0 /* sideInset */, animate && !disallowAnimate,
Tiger Huang4a7835f2019-11-06 00:07:56 +08001146 mForceWindowDrawsBarBackgrounds, state);
Jorim Jaggi6482df52019-06-26 17:35:32 +02001147 boolean oldDrawLegacy = mDrawLegacyNavigationBarBackground;
Jorim Jaggi86d30ff2019-06-11 17:54:07 +02001148 mDrawLegacyNavigationBarBackground = mNavigationColorViewState.visible
1149 && (mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0;
Jorim Jaggi6482df52019-06-26 17:35:32 +02001150 if (oldDrawLegacy != mDrawLegacyNavigationBarBackground) {
1151 ViewRootImpl vri = getViewRootImpl();
1152 if (vri != null) {
1153 vri.requestInvalidateRootRenderNode();
1154 }
1155 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001156
1157 boolean statusBarNeedsRightInset = navBarToRightEdge
1158 && mNavigationColorViewState.present;
Adrian Roos85d202b2016-06-02 16:27:47 -07001159 boolean statusBarNeedsLeftInset = navBarToLeftEdge
1160 && mNavigationColorViewState.present;
1161 int statusBarSideInset = statusBarNeedsRightInset ? mLastRightInset
1162 : statusBarNeedsLeftInset ? mLastLeftInset : 0;
Jorim Jaggi4fa78922015-11-30 17:13:56 -08001163 updateColorViewInt(mStatusColorViewState, sysUiVisibility,
Jason Monkea506c62017-09-01 12:40:06 -04001164 calculateStatusBarColor(), 0, mLastTopInset,
Adrian Roos85d202b2016-06-02 16:27:47 -07001165 false /* matchVertical */, statusBarNeedsLeftInset, statusBarSideInset,
1166 animate && !disallowAnimate,
Tiger Huang4a7835f2019-11-06 00:07:56 +08001167 mForceWindowDrawsBarBackgrounds, state);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001168 }
1169
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001170 // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS or
1171 // mForceWindowDrawsBarBackgrounds, we still need to ensure that the rest of the view
1172 // hierarchy doesn't notice it, unless they've explicitly asked for it.
1173 //
1174 // Note: We don't need to check for IN_SCREEN or INSET_DECOR because unlike the status bar,
1175 // these flags wouldn't make the window draw behind the navigation bar, unless
1176 // LAYOUT_HIDE_NAVIGATION was set.
Tiger Huang4a7835f2019-11-06 00:07:56 +08001177 boolean hideNavigation = (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
1178 || !(state == null || state.getSource(ITYPE_NAVIGATION_BAR).isVisible());
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001179 boolean forceConsumingNavBar = (mForceWindowDrawsBarBackgrounds
1180 && (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
Wale Ogunwale8804af22015-11-17 09:18:15 -08001181 && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
Tiger Huang4a7835f2019-11-06 00:07:56 +08001182 && (attrs.getFitWindowInsetsTypes() & Type.navigationBars()) != 0
Adrian Roosfaba4062019-05-14 15:27:17 +02001183 && !hideNavigation)
1184 || (mLastShouldAlwaysConsumeSystemBars && hideNavigation);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001185
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001186 boolean consumingNavBar =
1187 ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
1188 && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
Tiger Huang4a7835f2019-11-06 00:07:56 +08001189 && (attrs.getFitWindowInsetsTypes() & Type.navigationBars()) != 0
Adrian Roosfaba4062019-05-14 15:27:17 +02001190 && !hideNavigation)
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001191 || forceConsumingNavBar;
1192
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001193 // If we didn't request fullscreen layout, but we still got it because of the
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001194 // mForceWindowDrawsBarBackgrounds flag, also consume top inset.
Jorim Jaggi01d60d02019-05-07 17:10:42 +02001195 // If we should always consume system bars, only consume that if the app wanted to go to
1196 // fullscreen, as othrewise we can expect the app to handle it.
1197 boolean fullscreen = (sysUiVisibility & SYSTEM_UI_FLAG_FULLSCREEN) != 0
Tiger Huang4a7835f2019-11-06 00:07:56 +08001198 || (attrs.flags & FLAG_FULLSCREEN) != 0
1199 || !(state == null || state.getSource(ITYPE_STATUS_BAR).isVisible());
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001200 boolean consumingStatusBar = (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == 0
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001201 && (attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0
1202 && (attrs.flags & FLAG_LAYOUT_INSET_DECOR) == 0
Tiger Huang4a7835f2019-11-06 00:07:56 +08001203 && (attrs.getFitWindowInsetsTypes() & Type.statusBars()) != 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001204 && mForceWindowDrawsBarBackgrounds
Brad Stenninge0573692019-03-11 13:52:46 -07001205 && mLastTopInset != 0
Jorim Jaggi01d60d02019-05-07 17:10:42 +02001206 || (mLastShouldAlwaysConsumeSystemBars && fullscreen);
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001207
Tiger Huang4a7835f2019-11-06 00:07:56 +08001208 int sides = attrs.getFitWindowInsetsSides();
1209 int consumedTop = consumingStatusBar && (sides & Side.TOP) != 0 ? mLastTopInset : 0;
1210 int consumedRight = consumingNavBar && (sides & Side.RIGHT) != 0 ? mLastRightInset : 0;
1211 int consumedBottom = consumingNavBar && (sides & Side.BOTTOM) != 0 ? mLastBottomInset : 0;
1212 int consumedLeft = consumingNavBar && (sides & Side.LEFT) != 0 ? mLastLeftInset : 0;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001213
1214 if (mContentRoot != null
1215 && mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
1216 MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001217 if (lp.topMargin != consumedTop || lp.rightMargin != consumedRight
Adrian Roos85d202b2016-06-02 16:27:47 -07001218 || lp.bottomMargin != consumedBottom || lp.leftMargin != consumedLeft) {
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001219 lp.topMargin = consumedTop;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001220 lp.rightMargin = consumedRight;
1221 lp.bottomMargin = consumedBottom;
Adrian Roos85d202b2016-06-02 16:27:47 -07001222 lp.leftMargin = consumedLeft;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001223 mContentRoot.setLayoutParams(lp);
1224
1225 if (insets == null) {
1226 // The insets have changed, but we're not currently in the process
1227 // of dispatching them.
1228 requestApplyInsets();
1229 }
1230 }
1231 if (insets != null) {
Adrian Roosf7b74262017-11-22 14:21:01 +01001232 insets = insets.inset(consumedLeft, consumedTop, consumedRight, consumedBottom);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001233 }
1234 }
1235
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001236 if (forceConsumingNavBar) {
1237 mBackgroundInsets = Insets.of(mLastLeftInset, 0, mLastRightInset, mLastBottomInset);
1238 } else {
1239 mBackgroundInsets = Insets.NONE;
1240 }
1241 updateBackgroundDrawable();
1242
Wale Ogunwale8804af22015-11-17 09:18:15 -08001243 if (insets != null) {
1244 insets = insets.consumeStableInsets();
1245 }
1246 return insets;
1247 }
1248
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001249 /**
1250 * Updates the background drawable, applying padding to it in case we {@link #mBackgroundInsets}
1251 * are set.
1252 */
1253 private void updateBackgroundDrawable() {
Jorim Jaggid798fd32019-05-08 23:08:02 +02001254 // Background insets can be null if super constructor calls setBackgroundDrawable.
1255 if (mBackgroundInsets == null) {
1256 mBackgroundInsets = Insets.NONE;
1257 }
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001258 if (mBackgroundInsets.equals(mLastBackgroundInsets)
1259 && mLastOriginalBackgroundDrawable == mOriginalBackgroundDrawable) {
1260 return;
1261 }
Jorim Jaggi1ed68892019-04-08 14:51:42 +02001262 if (mOriginalBackgroundDrawable == null || mBackgroundInsets.equals(Insets.NONE)) {
Jorim Jaggi24cf50f2019-04-09 15:16:23 +02001263
1264 // Call super since we are intercepting setBackground on this class.
1265 super.setBackgroundDrawable(mOriginalBackgroundDrawable);
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001266 } else {
Jorim Jaggi24cf50f2019-04-09 15:16:23 +02001267
1268 // Call super since we are intercepting setBackground on this class.
1269 super.setBackgroundDrawable(new InsetDrawable(mOriginalBackgroundDrawable,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001270 mBackgroundInsets.left, mBackgroundInsets.top,
1271 mBackgroundInsets.right, mBackgroundInsets.bottom) {
1272
1273 /**
1274 * Return inner padding so we don't apply the padding again in
1275 * {@link DecorView#drawableChanged()}
1276 */
1277 @Override
1278 public boolean getPadding(Rect padding) {
1279 return getDrawable().getPadding(padding);
1280 }
1281 });
1282 }
1283 mLastBackgroundInsets = mBackgroundInsets;
1284 mLastOriginalBackgroundDrawable = mOriginalBackgroundDrawable;
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001285 }
1286
Jorim Jaggi24cf50f2019-04-09 15:16:23 +02001287 @Override
1288 public Drawable getBackground() {
1289 return mOriginalBackgroundDrawable;
1290 }
1291
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001292 private int calculateStatusBarColor() {
1293 return calculateBarColor(mWindow.getAttributes().flags, FLAG_TRANSLUCENT_STATUS,
Adrian Roos4c864592019-04-10 14:47:57 +02001294 mSemiTransparentBarColor, mWindow.mStatusBarColor,
1295 getWindowSystemUiVisibility(), SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
1296 mWindow.mEnsureStatusBarContrastWhenTransparent);
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001297 }
1298
1299 private int calculateNavigationBarColor() {
1300 return calculateBarColor(mWindow.getAttributes().flags, FLAG_TRANSLUCENT_NAVIGATION,
Adrian Roos4c864592019-04-10 14:47:57 +02001301 mSemiTransparentBarColor, mWindow.mNavigationBarColor,
1302 getWindowSystemUiVisibility(), SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
1303 mWindow.mEnsureNavigationBarContrastWhenTransparent
1304 && getContext().getResources().getBoolean(R.bool.config_navBarNeedsScrim));
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001305 }
1306
1307 public static int calculateBarColor(int flags, int translucentFlag, int semiTransparentBarColor,
Adrian Roos4c864592019-04-10 14:47:57 +02001308 int barColor, int sysuiVis, int lightSysuiFlag, boolean scrimTransparent) {
1309 if ((flags & translucentFlag) != 0) {
1310 return semiTransparentBarColor;
1311 } else if ((flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
1312 return Color.BLACK;
Winson Chungffc70a62019-07-01 15:32:43 -07001313 } else if (scrimTransparent && Color.alpha(barColor) == 0) {
Adrian Roos4c864592019-04-10 14:47:57 +02001314 boolean light = (sysuiVis & lightSysuiFlag) != 0;
1315 return light ? SCRIM_LIGHT : semiTransparentBarColor;
1316 } else {
1317 return barColor;
1318 }
Jorim Jaggi4fa78922015-11-30 17:13:56 -08001319 }
1320
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001321 private int getCurrentColor(ColorViewState state) {
1322 if (state.visible) {
1323 return state.color;
1324 } else {
1325 return 0;
1326 }
1327 }
1328
Wale Ogunwale8804af22015-11-17 09:18:15 -08001329 /**
1330 * Update a color view
1331 *
1332 * @param state the color view to update.
1333 * @param sysUiVis the current systemUiVisibility to apply.
1334 * @param color the current color to apply.
Jason Monkea506c62017-09-01 12:40:06 -04001335 * @param dividerColor the current divider color to apply.
Wale Ogunwale8804af22015-11-17 09:18:15 -08001336 * @param size the current size in the non-parent-matching dimension.
1337 * @param verticalBar if true the view is attached to a vertical edge, otherwise to a
1338 * horizontal edge,
Adrian Roos85d202b2016-06-02 16:27:47 -07001339 * @param sideMargin sideMargin for the color view.
Wale Ogunwale8804af22015-11-17 09:18:15 -08001340 * @param animate if true, the change will be animated.
1341 */
1342 private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
Jason Monkea506c62017-09-01 12:40:06 -04001343 int dividerColor, int size, boolean verticalBar, boolean seascape, int sideMargin,
Tiger Huang4a7835f2019-11-06 00:07:56 +08001344 boolean animate, boolean force, InsetsState insetsState) {
1345 state.present = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
1346 ? state.attributes.isPresent(sysUiVis, mWindow.getAttributes().flags, force)
1347 : state.attributes.isPresent(insetsState, mWindow.getAttributes().flags, force);
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001348 boolean show = state.attributes.isVisible(state.present, color,
1349 mWindow.getAttributes().flags, force);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001350 boolean showView = show && !isResizing() && size > 0;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001351
1352 boolean visibilityChanged = false;
1353 View view = state.view;
1354
1355 int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size;
1356 int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT;
Adrian Roos85d202b2016-06-02 16:27:47 -07001357 int resolvedGravity = verticalBar
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001358 ? (seascape ? state.attributes.seascapeGravity : state.attributes.horizontalGravity)
1359 : state.attributes.verticalGravity;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001360
1361 if (view == null) {
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001362 if (showView) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001363 state.view = view = new View(mContext);
Jason Monkea506c62017-09-01 12:40:06 -04001364 setColor(view, color, dividerColor, verticalBar, seascape);
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001365 view.setTransitionName(state.attributes.transitionName);
1366 view.setId(state.attributes.id);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001367 visibilityChanged = true;
1368 view.setVisibility(INVISIBLE);
1369 state.targetVisibility = VISIBLE;
1370
1371 LayoutParams lp = new LayoutParams(resolvedWidth, resolvedHeight,
1372 resolvedGravity);
Adrian Roos85d202b2016-06-02 16:27:47 -07001373 if (seascape) {
1374 lp.leftMargin = sideMargin;
1375 } else {
1376 lp.rightMargin = sideMargin;
1377 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001378 addView(view, lp);
1379 updateColorViewTranslations();
1380 }
1381 } else {
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001382 int vis = showView ? VISIBLE : INVISIBLE;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001383 visibilityChanged = state.targetVisibility != vis;
1384 state.targetVisibility = vis;
1385 LayoutParams lp = (LayoutParams) view.getLayoutParams();
Adrian Roos85d202b2016-06-02 16:27:47 -07001386 int rightMargin = seascape ? 0 : sideMargin;
1387 int leftMargin = seascape ? sideMargin : 0;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001388 if (lp.height != resolvedHeight || lp.width != resolvedWidth
Adrian Roos85d202b2016-06-02 16:27:47 -07001389 || lp.gravity != resolvedGravity || lp.rightMargin != rightMargin
1390 || lp.leftMargin != leftMargin) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001391 lp.height = resolvedHeight;
1392 lp.width = resolvedWidth;
1393 lp.gravity = resolvedGravity;
1394 lp.rightMargin = rightMargin;
Adrian Roos85d202b2016-06-02 16:27:47 -07001395 lp.leftMargin = leftMargin;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001396 view.setLayoutParams(lp);
1397 }
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001398 if (showView) {
Jason Monkea506c62017-09-01 12:40:06 -04001399 setColor(view, color, dividerColor, verticalBar, seascape);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001400 }
1401 }
1402 if (visibilityChanged) {
1403 view.animate().cancel();
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001404 if (animate && !isResizing()) {
1405 if (showView) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001406 if (view.getVisibility() != VISIBLE) {
1407 view.setVisibility(VISIBLE);
1408 view.setAlpha(0.0f);
1409 }
1410 view.animate().alpha(1.0f).setInterpolator(mShowInterpolator).
1411 setDuration(mBarEnterExitDuration);
1412 } else {
1413 view.animate().alpha(0.0f).setInterpolator(mHideInterpolator)
1414 .setDuration(mBarEnterExitDuration)
1415 .withEndAction(new Runnable() {
1416 @Override
1417 public void run() {
1418 state.view.setAlpha(1.0f);
1419 state.view.setVisibility(INVISIBLE);
1420 }
1421 });
1422 }
1423 } else {
1424 view.setAlpha(1.0f);
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001425 view.setVisibility(showView ? VISIBLE : INVISIBLE);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001426 }
1427 }
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001428 state.visible = show;
1429 state.color = color;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001430 }
1431
Jason Monkea506c62017-09-01 12:40:06 -04001432 private static void setColor(View v, int color, int dividerColor, boolean verticalBar,
1433 boolean seascape) {
1434 if (dividerColor != 0) {
1435 final Pair<Boolean, Boolean> dir = (Pair<Boolean, Boolean>) v.getTag();
1436 if (dir == null || dir.first != verticalBar || dir.second != seascape) {
1437 final int size = Math.round(
1438 TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
1439 v.getContext().getResources().getDisplayMetrics()));
1440 // Use an inset to make the divider line on the side that faces the app.
1441 final InsetDrawable d = new InsetDrawable(new ColorDrawable(color),
1442 verticalBar && !seascape ? size : 0,
1443 !verticalBar ? size : 0,
1444 verticalBar && seascape ? size : 0, 0);
1445 v.setBackground(new LayerDrawable(new Drawable[] {
1446 new ColorDrawable(dividerColor), d }));
1447 v.setTag(new Pair<>(verticalBar, seascape));
1448 } else {
1449 final LayerDrawable d = (LayerDrawable) v.getBackground();
1450 final InsetDrawable inset = ((InsetDrawable) d.getDrawable(1));
1451 ((ColorDrawable) inset.getDrawable()).setColor(color);
1452 ((ColorDrawable) d.getDrawable(0)).setColor(dividerColor);
1453 }
1454 } else {
1455 v.setTag(null);
1456 v.setBackgroundColor(color);
1457 }
1458 }
1459
Wale Ogunwale8804af22015-11-17 09:18:15 -08001460 private void updateColorViewTranslations() {
1461 // Put the color views back in place when they get moved off the screen
1462 // due to the the ViewRootImpl panning.
1463 int rootScrollY = mRootScrollY;
1464 if (mStatusColorViewState.view != null) {
1465 mStatusColorViewState.view.setTranslationY(rootScrollY > 0 ? rootScrollY : 0);
1466 }
1467 if (mNavigationColorViewState.view != null) {
1468 mNavigationColorViewState.view.setTranslationY(rootScrollY < 0 ? rootScrollY : 0);
1469 }
1470 }
1471
1472 private WindowInsets updateStatusGuard(WindowInsets insets) {
1473 boolean showStatusGuard = false;
1474 // Show the status guard when the non-overlay contextual action bar is showing
1475 if (mPrimaryActionModeView != null) {
1476 if (mPrimaryActionModeView.getLayoutParams() instanceof MarginLayoutParams) {
1477 // Insets are magic!
1478 final MarginLayoutParams mlp = (MarginLayoutParams)
1479 mPrimaryActionModeView.getLayoutParams();
1480 boolean mlpChanged = false;
1481 if (mPrimaryActionModeView.isShown()) {
1482 if (mTempRect == null) {
1483 mTempRect = new Rect();
1484 }
1485 final Rect rect = mTempRect;
1486
Adrian Roos27db0ca2019-05-29 16:12:09 +02001487 // Apply the insets that have not been applied by the contentParent yet.
1488 WindowInsets innerInsets =
1489 mWindow.mContentParent.computeSystemWindowInsets(insets, rect);
1490 int newTopMargin = innerInsets.getSystemWindowInsetTop();
1491 int newLeftMargin = innerInsets.getSystemWindowInsetLeft();
1492 int newRightMargin = innerInsets.getSystemWindowInsetRight();
Wale Ogunwale8804af22015-11-17 09:18:15 -08001493
Adrian Roos27db0ca2019-05-29 16:12:09 +02001494 // Must use root window insets for the guard, because the color views consume
1495 // the navigation bar inset if the window does not request LAYOUT_HIDE_NAV - but
1496 // the status guard is attached at the root.
1497 WindowInsets rootInsets = getRootWindowInsets();
1498 int newGuardLeftMargin = rootInsets.getSystemWindowInsetLeft();
1499 int newGuardRightMargin = rootInsets.getSystemWindowInsetRight();
1500
1501 if (mlp.topMargin != newTopMargin || mlp.leftMargin != newLeftMargin
1502 || mlp.rightMargin != newRightMargin) {
1503 mlpChanged = true;
1504 mlp.topMargin = newTopMargin;
1505 mlp.leftMargin = newLeftMargin;
1506 mlp.rightMargin = newRightMargin;
1507 }
1508
1509 if (newTopMargin > 0 && mStatusGuard == null) {
1510 mStatusGuard = new View(mContext);
1511 mStatusGuard.setVisibility(GONE);
1512 final LayoutParams lp = new LayoutParams(MATCH_PARENT,
1513 mlp.topMargin, Gravity.LEFT | Gravity.TOP);
1514 lp.leftMargin = newGuardLeftMargin;
1515 lp.rightMargin = newGuardRightMargin;
1516 addView(mStatusGuard, indexOfChild(mStatusColorViewState.view), lp);
1517 } else if (mStatusGuard != null) {
1518 final LayoutParams lp = (LayoutParams)
1519 mStatusGuard.getLayoutParams();
1520 if (lp.height != mlp.topMargin || lp.leftMargin != newGuardLeftMargin
1521 || lp.rightMargin != newGuardRightMargin) {
1522 lp.height = mlp.topMargin;
1523 lp.leftMargin = newGuardLeftMargin;
1524 lp.rightMargin = newGuardRightMargin;
1525 mStatusGuard.setLayoutParams(lp);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001526 }
1527 }
1528
1529 // The action mode's theme may differ from the app, so
1530 // always show the status guard above it if we have one.
1531 showStatusGuard = mStatusGuard != null;
1532
Adrian Roos27db0ca2019-05-29 16:12:09 +02001533 if (showStatusGuard && mStatusGuard.getVisibility() != VISIBLE) {
1534 // If it wasn't previously shown, the color may be stale
1535 updateStatusGuardColor();
1536 }
1537
Wale Ogunwale8804af22015-11-17 09:18:15 -08001538 // We only need to consume the insets if the action
1539 // mode is overlaid on the app content (e.g. it's
1540 // sitting in a FrameLayout, see
1541 // screen_simple_overlay_action_mode.xml).
1542 final boolean nonOverlay = (mWindow.getLocalFeaturesPrivate()
1543 & (1 << Window.FEATURE_ACTION_MODE_OVERLAY)) == 0;
Adrian Roosf7b74262017-11-22 14:21:01 +01001544 if (nonOverlay && showStatusGuard) {
1545 insets = insets.inset(0, insets.getSystemWindowInsetTop(), 0, 0);
1546 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001547 } else {
1548 // reset top margin
Adrian Roos27db0ca2019-05-29 16:12:09 +02001549 if (mlp.topMargin != 0 || mlp.leftMargin != 0 || mlp.rightMargin != 0) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001550 mlpChanged = true;
1551 mlp.topMargin = 0;
1552 }
1553 }
1554 if (mlpChanged) {
1555 mPrimaryActionModeView.setLayoutParams(mlp);
1556 }
1557 }
1558 }
1559 if (mStatusGuard != null) {
Adrian Roos27db0ca2019-05-29 16:12:09 +02001560 mStatusGuard.setVisibility(showStatusGuard ? VISIBLE : GONE);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001561 }
1562 return insets;
1563 }
1564
Adrian Roos27db0ca2019-05-29 16:12:09 +02001565 private void updateStatusGuardColor() {
1566 boolean lightStatusBar =
1567 (getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
1568 mStatusGuard.setBackgroundColor(lightStatusBar
1569 ? mContext.getColor(R.color.decor_view_status_guard_light)
1570 : mContext.getColor(R.color.decor_view_status_guard));
1571 }
1572
Winson Chung4d8681f2017-05-23 16:22:08 -07001573 /**
1574 * Overrides the view outline when the activity enters picture-in-picture to ensure that it has
1575 * an opaque shadow even if the window background is completely transparent. This only applies
1576 * to activities that are currently the task root.
1577 */
1578 public void updatePictureInPictureOutlineProvider(boolean isInPictureInPictureMode) {
1579 if (mIsInPictureInPictureMode == isInPictureInPictureMode) {
1580 return;
1581 }
1582
1583 if (isInPictureInPictureMode) {
1584 final Window.WindowControllerCallback callback =
1585 mWindow.getWindowControllerCallback();
1586 if (callback != null && callback.isTaskRoot()) {
1587 // Call super implementation directly as we don't want to save the PIP outline
1588 // provider to be restored
1589 super.setOutlineProvider(PIP_OUTLINE_PROVIDER);
1590 }
1591 } else {
1592 // Restore the previous outline provider
1593 if (getOutlineProvider() != mLastOutlineProvider) {
1594 setOutlineProvider(mLastOutlineProvider);
1595 }
1596 }
1597 mIsInPictureInPictureMode = isInPictureInPictureMode;
1598 }
1599
1600 @Override
1601 public void setOutlineProvider(ViewOutlineProvider provider) {
1602 super.setOutlineProvider(provider);
1603
1604 // Save the outline provider set to ensure that we can restore when the activity leaves PiP
1605 mLastOutlineProvider = provider;
1606 }
1607
Wale Ogunwale8804af22015-11-17 09:18:15 -08001608 private void drawableChanged() {
1609 if (mChanging) {
1610 return;
1611 }
1612
Jorim Jaggid798fd32019-05-08 23:08:02 +02001613 // Fields can be null if super constructor calls setBackgroundDrawable.
1614 Rect framePadding = mFramePadding != null ? mFramePadding : new Rect();
1615 Rect backgroundPadding = mBackgroundPadding != null ? mBackgroundPadding : new Rect();
1616
1617 setPadding(framePadding.left + backgroundPadding.left,
1618 framePadding.top + backgroundPadding.top,
1619 framePadding.right + backgroundPadding.right,
1620 framePadding.bottom + backgroundPadding.bottom);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001621 requestLayout();
1622 invalidate();
1623
1624 int opacity = PixelFormat.OPAQUE;
Wale Ogunwale3382ab12017-07-27 08:55:03 -07001625 final WindowConfiguration winConfig = getResources().getConfiguration().windowConfiguration;
1626 if (winConfig.hasWindowShadow()) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001627 // If the window has a shadow, it must be translucent.
1628 opacity = PixelFormat.TRANSLUCENT;
1629 } else{
1630 // Note: If there is no background, we will assume opaque. The
1631 // common case seems to be that an application sets there to be
1632 // no background so it can draw everything itself. For that,
1633 // we would like to assume OPAQUE and let the app force it to
1634 // the slower TRANSLUCENT mode if that is really what it wants.
1635 Drawable bg = getBackground();
1636 Drawable fg = getForeground();
1637 if (bg != null) {
1638 if (fg == null) {
1639 opacity = bg.getOpacity();
Jorim Jaggid798fd32019-05-08 23:08:02 +02001640 } else if (framePadding.left <= 0 && framePadding.top <= 0
1641 && framePadding.right <= 0 && framePadding.bottom <= 0) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001642 // If the frame padding is zero, then we can be opaque
1643 // if either the frame -or- the background is opaque.
1644 int fop = fg.getOpacity();
1645 int bop = bg.getOpacity();
1646 if (false)
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001647 Log.v(mLogTag, "Background opacity: " + bop + ", Frame opacity: " + fop);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001648 if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
1649 opacity = PixelFormat.OPAQUE;
1650 } else if (fop == PixelFormat.UNKNOWN) {
1651 opacity = bop;
1652 } else if (bop == PixelFormat.UNKNOWN) {
1653 opacity = fop;
1654 } else {
1655 opacity = Drawable.resolveOpacity(fop, bop);
1656 }
1657 } else {
1658 // For now we have to assume translucent if there is a
1659 // frame with padding... there is no way to tell if the
1660 // frame and background together will draw all pixels.
1661 if (false)
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001662 Log.v(mLogTag, "Padding: " + mFramePadding);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001663 opacity = PixelFormat.TRANSLUCENT;
1664 }
1665 }
1666 if (false)
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001667 Log.v(mLogTag, "Background: " + bg + ", Frame: " + fg);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001668 }
1669
1670 if (false)
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001671 Log.v(mLogTag, "Selected default opacity: " + opacity);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001672
1673 mDefaultOpacity = opacity;
1674 if (mFeatureId < 0) {
1675 mWindow.setDefaultWindowFormat(opacity);
1676 }
1677 }
1678
1679 @Override
1680 public void onWindowFocusChanged(boolean hasWindowFocus) {
1681 super.onWindowFocusChanged(hasWindowFocus);
1682
1683 // If the user is chording a menu shortcut, release the chord since
1684 // this window lost focus
1685 if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL) && !hasWindowFocus
1686 && mWindow.mPanelChordingKey != 0) {
1687 mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);
1688 }
1689
1690 final Window.Callback cb = mWindow.getCallback();
1691 if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
1692 cb.onWindowFocusChanged(hasWindowFocus);
1693 }
1694
1695 if (mPrimaryActionMode != null) {
1696 mPrimaryActionMode.onWindowFocusChanged(hasWindowFocus);
1697 }
1698 if (mFloatingActionMode != null) {
1699 mFloatingActionMode.onWindowFocusChanged(hasWindowFocus);
1700 }
Wale Ogunwale2b547c32015-11-18 10:33:22 -08001701
1702 updateElevation();
Wale Ogunwale8804af22015-11-17 09:18:15 -08001703 }
1704
1705 @Override
1706 protected void onAttachedToWindow() {
1707 super.onAttachedToWindow();
1708
1709 final Window.Callback cb = mWindow.getCallback();
1710 if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
1711 cb.onAttachedToWindow();
1712 }
1713
1714 if (mFeatureId == -1) {
1715 /*
1716 * The main window has been attached, try to restore any panels
1717 * that may have been open before. This is called in cases where
1718 * an activity is being killed for configuration change and the
1719 * menu was open. When the activity is recreated, the menu
1720 * should be shown again.
1721 */
1722 mWindow.openPanelsAfterRestore();
1723 }
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08001724
1725 if (!mWindowResizeCallbacksAdded) {
1726 // If there is no window callback installed there was no window set before. Set it now.
1727 // Note that our ViewRootImpl object will not change.
1728 getViewRootImpl().addWindowCallbacks(this);
1729 mWindowResizeCallbacksAdded = true;
1730 } else if (mBackdropFrameRenderer != null) {
1731 // We are resizing and this call happened due to a configuration change. Tell the
1732 // renderer about it.
1733 mBackdropFrameRenderer.onConfigurationChange();
1734 }
Andrii Kulian51c1b672017-04-07 18:39:32 -07001735 mWindow.onViewRootImplSet(getViewRootImpl());
Wale Ogunwale8804af22015-11-17 09:18:15 -08001736 }
1737
1738 @Override
1739 protected void onDetachedFromWindow() {
1740 super.onDetachedFromWindow();
1741
1742 final Window.Callback cb = mWindow.getCallback();
1743 if (cb != null && mFeatureId < 0) {
1744 cb.onDetachedFromWindow();
1745 }
1746
1747 if (mWindow.mDecorContentParent != null) {
1748 mWindow.mDecorContentParent.dismissPopups();
1749 }
1750
1751 if (mPrimaryActionModePopup != null) {
1752 removeCallbacks(mShowPrimaryActionModePopup);
1753 if (mPrimaryActionModePopup.isShowing()) {
1754 mPrimaryActionModePopup.dismiss();
1755 }
1756 mPrimaryActionModePopup = null;
1757 }
1758 if (mFloatingToolbar != null) {
1759 mFloatingToolbar.dismiss();
1760 mFloatingToolbar = null;
1761 }
1762
1763 PhoneWindow.PanelFeatureState st = mWindow.getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
1764 if (st != null && st.menu != null && mFeatureId < 0) {
1765 st.menu.close();
1766 }
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08001767
Jorim Jaggib2005a02016-04-08 14:13:30 -07001768 releaseThreadedRenderer();
1769
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08001770 if (mWindowResizeCallbacksAdded) {
1771 getViewRootImpl().removeWindowCallbacks(this);
1772 mWindowResizeCallbacksAdded = false;
1773 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001774 }
1775
1776 @Override
1777 public void onCloseSystemDialogs(String reason) {
1778 if (mFeatureId >= 0) {
1779 mWindow.closeAllPanels();
1780 }
1781 }
1782
1783 public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface() {
1784 return mFeatureId < 0 ? mWindow.mTakeSurfaceCallback : null;
1785 }
1786
1787 public InputQueue.Callback willYouTakeTheInputQueue() {
1788 return mFeatureId < 0 ? mWindow.mTakeInputQueueCallback : null;
1789 }
1790
1791 public void setSurfaceType(int type) {
1792 mWindow.setType(type);
1793 }
1794
1795 public void setSurfaceFormat(int format) {
1796 mWindow.setFormat(format);
1797 }
1798
1799 public void setSurfaceKeepScreenOn(boolean keepOn) {
1800 if (keepOn) mWindow.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1801 else mWindow.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1802 }
1803
1804 @Override
1805 public void onRootViewScrollYChanged(int rootScrollY) {
1806 mRootScrollY = rootScrollY;
Evan Rosky0d654cb2019-02-26 10:59:10 -08001807 if (mDecorCaptionView != null) {
1808 mDecorCaptionView.onRootViewScrollYChanged(rootScrollY);
1809 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001810 updateColorViewTranslations();
1811 }
1812
1813 private ActionMode createActionMode(
1814 int type, ActionMode.Callback2 callback, View originatingView) {
1815 switch (type) {
1816 case ActionMode.TYPE_PRIMARY:
1817 default:
1818 return createStandaloneActionMode(callback);
1819 case ActionMode.TYPE_FLOATING:
1820 return createFloatingActionMode(originatingView, callback);
1821 }
1822 }
1823
1824 private void setHandledActionMode(ActionMode mode) {
1825 if (mode.getType() == ActionMode.TYPE_PRIMARY) {
1826 setHandledPrimaryActionMode(mode);
1827 } else if (mode.getType() == ActionMode.TYPE_FLOATING) {
1828 setHandledFloatingActionMode(mode);
1829 }
1830 }
1831
1832 private ActionMode createStandaloneActionMode(ActionMode.Callback callback) {
1833 endOnGoingFadeAnimation();
1834 cleanupPrimaryActionMode();
Andrii Kulian8d6ac262016-06-08 13:14:19 -07001835 // We want to create new mPrimaryActionModeView in two cases: if there is no existing
1836 // instance at all, or if there is one, but it is detached from window. The latter case
1837 // might happen when app is resized in multi-window mode and decor view is preserved
1838 // along with the main app window. Keeping mPrimaryActionModeView reference doesn't cause
1839 // app memory leaks because killMode() is called when the dismiss animation ends and from
1840 // cleanupPrimaryActionMode() invocation above.
1841 if (mPrimaryActionModeView == null || !mPrimaryActionModeView.isAttachedToWindow()) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001842 if (mWindow.isFloating()) {
1843 // Use the action bar theme.
1844 final TypedValue outValue = new TypedValue();
1845 final Resources.Theme baseTheme = mContext.getTheme();
1846 baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
1847
1848 final Context actionBarContext;
1849 if (outValue.resourceId != 0) {
1850 final Resources.Theme actionBarTheme = mContext.getResources().newTheme();
1851 actionBarTheme.setTo(baseTheme);
1852 actionBarTheme.applyStyle(outValue.resourceId, true);
1853
1854 actionBarContext = new ContextThemeWrapper(mContext, 0);
1855 actionBarContext.getTheme().setTo(actionBarTheme);
1856 } else {
1857 actionBarContext = mContext;
1858 }
1859
1860 mPrimaryActionModeView = new ActionBarContextView(actionBarContext);
1861 mPrimaryActionModePopup = new PopupWindow(actionBarContext, null,
1862 R.attr.actionModePopupWindowStyle);
1863 mPrimaryActionModePopup.setWindowLayoutType(
1864 WindowManager.LayoutParams.TYPE_APPLICATION);
1865 mPrimaryActionModePopup.setContentView(mPrimaryActionModeView);
1866 mPrimaryActionModePopup.setWidth(MATCH_PARENT);
1867
1868 actionBarContext.getTheme().resolveAttribute(
1869 R.attr.actionBarSize, outValue, true);
1870 final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
1871 actionBarContext.getResources().getDisplayMetrics());
1872 mPrimaryActionModeView.setContentHeight(height);
1873 mPrimaryActionModePopup.setHeight(WRAP_CONTENT);
1874 mShowPrimaryActionModePopup = new Runnable() {
1875 public void run() {
1876 mPrimaryActionModePopup.showAtLocation(
1877 mPrimaryActionModeView.getApplicationWindowToken(),
1878 Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
1879 endOnGoingFadeAnimation();
Wale Ogunwale8804af22015-11-17 09:18:15 -08001880
Chris Banese65b3fb2016-06-01 11:39:54 +01001881 if (shouldAnimatePrimaryActionModeView()) {
1882 mFadeAnim = ObjectAnimator.ofFloat(mPrimaryActionModeView, View.ALPHA,
1883 0f, 1f);
1884 mFadeAnim.addListener(new AnimatorListenerAdapter() {
1885 @Override
1886 public void onAnimationStart(Animator animation) {
1887 mPrimaryActionModeView.setVisibility(VISIBLE);
1888 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001889
Chris Banese65b3fb2016-06-01 11:39:54 +01001890 @Override
1891 public void onAnimationEnd(Animator animation) {
1892 mPrimaryActionModeView.setAlpha(1f);
1893 mFadeAnim = null;
1894 }
1895 });
1896 mFadeAnim.start();
1897 } else {
1898 mPrimaryActionModeView.setAlpha(1f);
1899 mPrimaryActionModeView.setVisibility(VISIBLE);
1900 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001901 }
1902 };
1903 } else {
Alan Viverette51efddb2017-04-05 10:00:01 -04001904 ViewStub stub = findViewById(R.id.action_mode_bar_stub);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001905 if (stub != null) {
1906 mPrimaryActionModeView = (ActionBarContextView) stub.inflate();
Andrii Kulian8d6ac262016-06-08 13:14:19 -07001907 mPrimaryActionModePopup = null;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001908 }
1909 }
1910 }
1911 if (mPrimaryActionModeView != null) {
1912 mPrimaryActionModeView.killMode();
1913 ActionMode mode = new StandaloneActionMode(
1914 mPrimaryActionModeView.getContext(), mPrimaryActionModeView,
1915 callback, mPrimaryActionModePopup == null);
1916 return mode;
1917 }
1918 return null;
1919 }
1920
1921 private void endOnGoingFadeAnimation() {
1922 if (mFadeAnim != null) {
1923 mFadeAnim.end();
1924 }
1925 }
1926
1927 private void setHandledPrimaryActionMode(ActionMode mode) {
1928 endOnGoingFadeAnimation();
1929 mPrimaryActionMode = mode;
1930 mPrimaryActionMode.invalidate();
1931 mPrimaryActionModeView.initForMode(mPrimaryActionMode);
1932 if (mPrimaryActionModePopup != null) {
1933 post(mShowPrimaryActionModePopup);
1934 } else {
Chris Banese65b3fb2016-06-01 11:39:54 +01001935 if (shouldAnimatePrimaryActionModeView()) {
1936 mFadeAnim = ObjectAnimator.ofFloat(mPrimaryActionModeView, View.ALPHA, 0f, 1f);
1937 mFadeAnim.addListener(new AnimatorListenerAdapter() {
1938 @Override
1939 public void onAnimationStart(Animator animation) {
1940 mPrimaryActionModeView.setVisibility(View.VISIBLE);
1941 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001942
Chris Banese65b3fb2016-06-01 11:39:54 +01001943 @Override
1944 public void onAnimationEnd(Animator animation) {
1945 mPrimaryActionModeView.setAlpha(1f);
1946 mFadeAnim = null;
1947 }
1948 });
1949 mFadeAnim.start();
1950 } else {
1951 mPrimaryActionModeView.setAlpha(1f);
1952 mPrimaryActionModeView.setVisibility(View.VISIBLE);
1953 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001954 }
1955 mPrimaryActionModeView.sendAccessibilityEvent(
1956 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
1957 }
1958
Chris Banese65b3fb2016-06-01 11:39:54 +01001959 boolean shouldAnimatePrimaryActionModeView() {
1960 // We only to animate the action mode in if the decor has already been laid out.
1961 // If it hasn't been laid out, it hasn't been drawn to screen yet.
1962 return isLaidOut();
1963 }
1964
Wale Ogunwale8804af22015-11-17 09:18:15 -08001965 private ActionMode createFloatingActionMode(
1966 View originatingView, ActionMode.Callback2 callback) {
1967 if (mFloatingActionMode != null) {
1968 mFloatingActionMode.finish();
1969 }
1970 cleanupFloatingActionModeViews();
Tarandeep Singhc9c83a92017-08-29 14:39:22 -07001971 mFloatingToolbar = new FloatingToolbar(mWindow);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001972 final FloatingActionMode mode =
Abodunrinwa Toki17293cc2017-05-22 14:16:04 +01001973 new FloatingActionMode(mContext, callback, originatingView, mFloatingToolbar);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001974 mFloatingActionModeOriginatingView = originatingView;
1975 mFloatingToolbarPreDrawListener =
1976 new ViewTreeObserver.OnPreDrawListener() {
1977 @Override
1978 public boolean onPreDraw() {
1979 mode.updateViewLocationInWindow();
1980 return true;
1981 }
1982 };
1983 return mode;
1984 }
1985
1986 private void setHandledFloatingActionMode(ActionMode mode) {
1987 mFloatingActionMode = mode;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001988 mFloatingActionMode.invalidate(); // Will show the floating toolbar if necessary.
1989 mFloatingActionModeOriginatingView.getViewTreeObserver()
1990 .addOnPreDrawListener(mFloatingToolbarPreDrawListener);
1991 }
1992
1993 /**
Wale Ogunwale62a91d62015-11-18 11:44:10 -08001994 * Informs the decor if the caption is attached and visible.
Wale Ogunwale8804af22015-11-17 09:18:15 -08001995 * @param attachedAndVisible true when the decor is visible.
Wale Ogunwale62a91d62015-11-18 11:44:10 -08001996 * Note that this will even be called if there is no caption.
Wale Ogunwale8804af22015-11-17 09:18:15 -08001997 **/
Wale Ogunwale62a91d62015-11-18 11:44:10 -08001998 void enableCaption(boolean attachedAndVisible) {
1999 if (mHasCaption != attachedAndVisible) {
2000 mHasCaption = attachedAndVisible;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002001 if (getForeground() != null) {
2002 drawableChanged();
2003 }
2004 }
2005 }
2006
Wale Ogunwale8804af22015-11-17 09:18:15 -08002007 void setWindow(PhoneWindow phoneWindow) {
2008 mWindow = phoneWindow;
2009 Context context = getContext();
2010 if (context instanceof DecorContext) {
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002011 DecorContext decorContext = (DecorContext) context;
2012 decorContext.setPhoneWindow(mWindow);
2013 }
Vadim Caen6932c772019-07-19 16:28:12 +02002014 if (mPendingWindowBackground != null) {
2015 Drawable background = mPendingWindowBackground;
2016 mPendingWindowBackground = null;
2017 setWindowBackground(background);
2018 }
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002019 }
2020
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002021 @Override
chaviwa213d302018-04-23 13:34:36 -07002022 public Resources getResources() {
2023 // Make sure the Resources object is propogated from the Context since it can be updated in
2024 // the Context object.
2025 return getContext().getResources();
2026 }
2027
2028 @Override
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002029 protected void onConfigurationChanged(Configuration newConfig) {
2030 super.onConfigurationChanged(newConfig);
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002031
Garfield Tan3b9613c2018-12-26 17:08:51 -08002032 updateDecorCaptionStatus(newConfig);
2033
2034 updateAvailableWidth();
2035 initializeElevation();
2036 }
2037
sanryhuang2ed879f2018-10-08 23:10:22 +08002038 @Override
2039 public void onMovedToDisplay(int displayId, Configuration config) {
2040 super.onMovedToDisplay(displayId, config);
2041 // Have to explicitly update displayId because it may use DecorContext
2042 getContext().updateDisplay(displayId);
2043 }
2044
Garfield Tan3b9613c2018-12-26 17:08:51 -08002045 /**
2046 * Determines if the workspace is entirely covered by the window.
2047 * @return {@code true} when the window is filling the entire screen/workspace.
2048 **/
2049 private boolean isFillingScreen(Configuration config) {
2050 final boolean isFullscreen = config.windowConfiguration.getWindowingMode()
2051 == WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
2052 return isFullscreen && (0 != ((getWindowSystemUiVisibility() | getSystemUiVisibility())
Yunfan Chen1831e8e2019-04-24 15:54:49 +09002053 & View.SYSTEM_UI_FLAG_FULLSCREEN));
Garfield Tan3b9613c2018-12-26 17:08:51 -08002054 }
2055
2056 private void updateDecorCaptionStatus(Configuration config) {
2057 final boolean displayWindowDecor = config.windowConfiguration.hasWindowDecorCaption()
2058 && !isFillingScreen(config);
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002059 if (mDecorCaptionView == null && displayWindowDecor) {
2060 // Configuration now requires a caption.
2061 final LayoutInflater inflater = mWindow.getLayoutInflater();
2062 mDecorCaptionView = createDecorCaptionView(inflater);
2063 if (mDecorCaptionView != null) {
2064 if (mDecorCaptionView.getParent() == null) {
2065 addView(mDecorCaptionView, 0,
2066 new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
Wale Ogunwaleeb6722c2015-12-08 11:43:43 -08002067 }
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002068 removeView(mContentRoot);
2069 mDecorCaptionView.addView(mContentRoot,
2070 new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002071 }
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002072 } else if (mDecorCaptionView != null) {
2073 // We might have to change the kind of surface before we do anything else.
2074 mDecorCaptionView.onConfigurationChanged(displayWindowDecor);
2075 enableCaption(displayWindowDecor);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002076 }
2077 }
2078
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002079 void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002080 if (mBackdropFrameRenderer != null) {
Filip Gruszczynskia40fd092016-01-07 16:38:11 -08002081 loadBackgroundDrawablesIfNeeded();
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002082 mBackdropFrameRenderer.onResourcesLoaded(
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002083 this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08002084 mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
2085 getCurrentColor(mNavigationColorViewState));
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002086 }
2087
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002088 mDecorCaptionView = createDecorCaptionView(inflater);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002089 final View root = inflater.inflate(layoutResource, null);
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002090 if (mDecorCaptionView != null) {
2091 if (mDecorCaptionView.getParent() == null) {
2092 addView(mDecorCaptionView,
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002093 new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
2094 }
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002095 mDecorCaptionView.addView(root,
Filip Gruszczynski63250652015-11-18 14:43:01 -08002096 new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002097 } else {
Jorim Jaggi0a13bfd2016-02-04 18:34:50 -08002098
2099 // Put it below the color views.
2100 addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002101 }
2102 mContentRoot = (ViewGroup) root;
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002103 initializeElevation();
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002104 }
2105
Filip Gruszczynskia40fd092016-01-07 16:38:11 -08002106 private void loadBackgroundDrawablesIfNeeded() {
2107 if (mResizingBackgroundDrawable == null) {
Nader Jawad56c68bc2018-04-24 17:08:51 -07002108 mResizingBackgroundDrawable = getResizingBackgroundDrawable(mWindow.mBackgroundDrawable,
2109 mWindow.mBackgroundFallbackDrawable, mWindow.isTranslucent()
2110 || mWindow.isShowingWallpaper());
Winson Chung1af8eda2016-02-05 17:55:56 +00002111 if (mResizingBackgroundDrawable == null) {
2112 // We shouldn't really get here as the background fallback should be always
2113 // available since it is defaulted by the system.
2114 Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow);
2115 }
Filip Gruszczynskia40fd092016-01-07 16:38:11 -08002116 }
2117 if (mCaptionBackgroundDrawable == null) {
2118 mCaptionBackgroundDrawable = getContext().getDrawable(
2119 R.drawable.decor_caption_title_focused);
2120 }
Chong Zhang0df63d52016-02-24 15:39:53 -08002121 if (mResizingBackgroundDrawable != null) {
2122 mLastBackgroundDrawableCb = mResizingBackgroundDrawable.getCallback();
2123 mResizingBackgroundDrawable.setCallback(null);
2124 }
Filip Gruszczynskia40fd092016-01-07 16:38:11 -08002125 }
2126
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002127 // Free floating overlapping windows require a caption.
2128 private DecorCaptionView createDecorCaptionView(LayoutInflater inflater) {
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002129 DecorCaptionView decorCaptionView = null;
2130 for (int i = getChildCount() - 1; i >= 0 && decorCaptionView == null; i--) {
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002131 View view = getChildAt(i);
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002132 if (view instanceof DecorCaptionView) {
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002133 // The decor was most likely saved from a relaunch - so reuse it.
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002134 decorCaptionView = (DecorCaptionView) view;
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002135 removeViewAt(i);
2136 }
2137 }
2138 final WindowManager.LayoutParams attrs = mWindow.getAttributes();
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002139 final boolean isApplication = attrs.type == TYPE_BASE_APPLICATION ||
Chong Zhangfea963e2016-08-15 17:14:16 -07002140 attrs.type == TYPE_APPLICATION || attrs.type == TYPE_DRAWN_APPLICATION;
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002141 final WindowConfiguration winConfig = getResources().getConfiguration().windowConfiguration;
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002142 // Only a non floating application window on one of the allowed workspaces can get a caption
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002143 if (!mWindow.isFloating() && isApplication && winConfig.hasWindowDecorCaption()) {
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002144 // Dependent on the brightness of the used title we either use the
2145 // dark or the light button frame.
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002146 if (decorCaptionView == null) {
2147 decorCaptionView = inflateDecorCaptionView(inflater);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002148 }
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002149 decorCaptionView.setPhoneWindow(mWindow, true /*showDecor*/);
Wale Ogunwale8cc5a742015-11-17 15:41:05 -08002150 } else {
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002151 decorCaptionView = null;
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002152 }
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002153
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002154 // Tell the decor if it has a visible caption.
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002155 enableCaption(decorCaptionView != null);
2156 return decorCaptionView;
2157 }
2158
2159 private DecorCaptionView inflateDecorCaptionView(LayoutInflater inflater) {
2160 final Context context = getContext();
2161 // We make a copy of the inflater, so it has the right context associated with it.
2162 inflater = inflater.from(context);
2163 final DecorCaptionView view = (DecorCaptionView) inflater.inflate(R.layout.decor_caption,
2164 null);
2165 setDecorCaptionShade(context, view);
2166 return view;
2167 }
2168
2169 private void setDecorCaptionShade(Context context, DecorCaptionView view) {
2170 final int shade = mWindow.getDecorCaptionShade();
2171 switch (shade) {
2172 case DECOR_CAPTION_SHADE_LIGHT:
2173 setLightDecorCaptionShade(view);
2174 break;
2175 case DECOR_CAPTION_SHADE_DARK:
2176 setDarkDecorCaptionShade(view);
2177 break;
2178 default: {
2179 TypedValue value = new TypedValue();
2180 context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
2181 // We invert the shade depending on brightness of the theme. Dark shade for light
2182 // theme and vice versa. Thanks to this the buttons should be visible on the
2183 // background.
2184 if (Color.luminance(value.data) < 0.5) {
2185 setLightDecorCaptionShade(view);
2186 } else {
2187 setDarkDecorCaptionShade(view);
2188 }
2189 break;
2190 }
2191 }
2192 }
2193
2194 void updateDecorCaptionShade() {
2195 if (mDecorCaptionView != null) {
2196 setDecorCaptionShade(getContext(), mDecorCaptionView);
2197 }
2198 }
2199
2200 private void setLightDecorCaptionShade(DecorCaptionView view) {
2201 view.findViewById(R.id.maximize_window).setBackgroundResource(
2202 R.drawable.decor_maximize_button_light);
2203 view.findViewById(R.id.close_window).setBackgroundResource(
2204 R.drawable.decor_close_button_light);
2205 }
2206
2207 private void setDarkDecorCaptionShade(DecorCaptionView view) {
2208 view.findViewById(R.id.maximize_window).setBackgroundResource(
2209 R.drawable.decor_maximize_button_dark);
2210 view.findViewById(R.id.close_window).setBackgroundResource(
2211 R.drawable.decor_close_button_dark);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002212 }
2213
2214 /**
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002215 * Returns the color used to fill areas the app has not rendered content to yet when the
2216 * user is resizing the window of an activity in multi-window mode.
2217 */
Nader Jawad56c68bc2018-04-24 17:08:51 -07002218 public static Drawable getResizingBackgroundDrawable(@Nullable Drawable backgroundDrawable,
2219 @Nullable Drawable fallbackDrawable, boolean windowTranslucent) {
2220 if (backgroundDrawable != null) {
2221 return enforceNonTranslucentBackground(backgroundDrawable, windowTranslucent);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002222 }
2223
Nader Jawad56c68bc2018-04-24 17:08:51 -07002224 if (fallbackDrawable != null) {
2225 return enforceNonTranslucentBackground(fallbackDrawable, windowTranslucent);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002226 }
Jorim Jaggi8e879f12016-05-25 16:41:49 -07002227 return new ColorDrawable(Color.BLACK);
2228 }
2229
2230 /**
2231 * Enforces a drawable to be non-translucent to act as a background if needed, i.e. if the
2232 * window is not translucent.
2233 */
2234 private static Drawable enforceNonTranslucentBackground(Drawable drawable,
2235 boolean windowTranslucent) {
2236 if (!windowTranslucent && drawable instanceof ColorDrawable) {
2237 ColorDrawable colorDrawable = (ColorDrawable) drawable;
2238 int color = colorDrawable.getColor();
2239 if (Color.alpha(color) != 255) {
2240 ColorDrawable copy = (ColorDrawable) colorDrawable.getConstantState().newDrawable()
2241 .mutate();
2242 copy.setColor(
2243 Color.argb(255, Color.red(color), Color.green(color), Color.blue(color)));
2244 return copy;
2245 }
2246 }
2247 return drawable;
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002248 }
2249
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002250 void clearContentView() {
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002251 if (mDecorCaptionView != null) {
Filip Gruszczynski63250652015-11-18 14:43:01 -08002252 mDecorCaptionView.removeContentView();
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002253 } else {
Jorim Jaggi6e0ce282015-12-01 15:19:49 -08002254 // This window doesn't have caption, so we need to remove everything except our views
2255 // we might have added.
2256 for (int i = getChildCount() - 1; i >= 0; i--) {
2257 View v = getChildAt(i);
2258 if (v != mStatusColorViewState.view && v != mNavigationColorViewState.view
Yohei Yukawa8f162c62018-01-10 13:18:09 -08002259 && v != mStatusGuard) {
Jorim Jaggi6e0ce282015-12-01 15:19:49 -08002260 removeViewAt(i);
2261 }
2262 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08002263 }
2264 }
2265
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002266 @Override
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08002267 public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
2268 Rect stableInsets) {
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002269 if (mBackdropFrameRenderer != null) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08002270 mBackdropFrameRenderer.setTargetRect(newBounds, fullscreen, systemInsets, stableInsets);
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002271 }
2272 }
2273
2274 @Override
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08002275 public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002276 Rect stableInsets, int resizeMode) {
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002277 if (mWindow.isDestroyed()) {
2278 // If the owner's window is gone, we should not be able to come here anymore.
2279 releaseThreadedRenderer();
2280 return;
2281 }
2282 if (mBackdropFrameRenderer != null) {
2283 return;
2284 }
Stan Iliev45faba52016-06-28 13:33:15 -04002285 final ThreadedRenderer renderer = getThreadedRenderer();
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002286 if (renderer != null) {
Filip Gruszczynskia40fd092016-01-07 16:38:11 -08002287 loadBackgroundDrawablesIfNeeded();
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002288 mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer,
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002289 initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08002290 mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
2291 getCurrentColor(mNavigationColorViewState), fullscreen, systemInsets,
Garfield Tanfbd8ea62018-10-16 17:09:49 -07002292 stableInsets);
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002293
2294 // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
2295 // If we want to get the shadow shown while resizing, we would need to elevate a new
2296 // element which owns the caption and has the elevation.
2297 updateElevation();
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002298
2299 updateColorViews(null /* insets */, false);
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002300 }
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002301 mResizeMode = resizeMode;
2302 getViewRootImpl().requestInvalidateRootRenderNode();
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002303 }
2304
2305 @Override
2306 public void onWindowDragResizeEnd() {
2307 releaseThreadedRenderer();
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002308 updateColorViews(null /* insets */, false);
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002309 mResizeMode = RESIZE_MODE_INVALID;
2310 getViewRootImpl().requestInvalidateRootRenderNode();
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002311 }
2312
2313 @Override
2314 public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
2315 if (mBackdropFrameRenderer == null) {
2316 return false;
2317 }
2318 return mBackdropFrameRenderer.onContentDrawn(offsetX, offsetY, sizeX, sizeY);
2319 }
2320
2321 @Override
2322 public void onRequestDraw(boolean reportNextDraw) {
2323 if (mBackdropFrameRenderer != null) {
2324 mBackdropFrameRenderer.onRequestDraw(reportNextDraw);
2325 } else if (reportNextDraw) {
2326 // If render thread is gone, just report immediately.
2327 if (isAttachedToWindow()) {
2328 getViewRootImpl().reportDrawFinish();
2329 }
2330 }
2331 }
2332
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002333 @Override
John Reck32f140aa62018-10-04 15:08:24 -07002334 public void onPostDraw(RecordingCanvas canvas) {
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002335 drawResizingShadowIfNeeded(canvas);
Jorim Jaggi86d30ff2019-06-11 17:54:07 +02002336 drawLegacyNavigationBarBackground(canvas);
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002337 }
2338
2339 private void initResizingPaints() {
2340 final int startColor = mContext.getResources().getColor(
2341 R.color.resize_shadow_start_color, null);
2342 final int endColor = mContext.getResources().getColor(
2343 R.color.resize_shadow_end_color, null);
2344 final int middleColor = (startColor + endColor) / 2;
2345 mHorizontalResizeShadowPaint.setShader(new LinearGradient(
2346 0, 0, 0, mResizeShadowSize, new int[] { startColor, middleColor, endColor },
2347 new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
2348 mVerticalResizeShadowPaint.setShader(new LinearGradient(
2349 0, 0, mResizeShadowSize, 0, new int[] { startColor, middleColor, endColor },
2350 new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
2351 }
2352
John Reck32f140aa62018-10-04 15:08:24 -07002353 private void drawResizingShadowIfNeeded(RecordingCanvas canvas) {
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002354 if (mResizeMode != RESIZE_MODE_DOCKED_DIVIDER || mWindow.mIsFloating
2355 || mWindow.isTranslucent()
Jorim Jaggi8e879f12016-05-25 16:41:49 -07002356 || mWindow.isShowingWallpaper()) {
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002357 return;
2358 }
2359 canvas.save();
2360 canvas.translate(0, getHeight() - mFrameOffsets.bottom);
2361 canvas.drawRect(0, 0, getWidth(), mResizeShadowSize, mHorizontalResizeShadowPaint);
2362 canvas.restore();
2363 canvas.save();
2364 canvas.translate(getWidth() - mFrameOffsets.right, 0);
2365 canvas.drawRect(0, 0, mResizeShadowSize, getHeight(), mVerticalResizeShadowPaint);
2366 canvas.restore();
2367 }
2368
Jorim Jaggi86d30ff2019-06-11 17:54:07 +02002369 private void drawLegacyNavigationBarBackground(RecordingCanvas canvas) {
2370 if (!mDrawLegacyNavigationBarBackground) {
2371 return;
2372 }
2373 View v = mNavigationColorViewState.view;
2374 if (v == null) {
2375 return;
2376 }
2377 canvas.drawRect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom(),
2378 mLegacyNavigationBarBackgroundPaint);
2379 }
2380
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002381 /** Release the renderer thread which is usually done when the user stops resizing. */
2382 private void releaseThreadedRenderer() {
Chong Zhangd3fd96c2016-02-08 18:25:24 -08002383 if (mResizingBackgroundDrawable != null && mLastBackgroundDrawableCb != null) {
2384 mResizingBackgroundDrawable.setCallback(mLastBackgroundDrawableCb);
2385 mLastBackgroundDrawableCb = null;
2386 }
2387
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002388 if (mBackdropFrameRenderer != null) {
2389 mBackdropFrameRenderer.releaseRenderer();
2390 mBackdropFrameRenderer = null;
2391 // Bring the shadow back.
2392 updateElevation();
2393 }
2394 }
2395
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002396 private boolean isResizing() {
2397 return mBackdropFrameRenderer != null;
2398 }
2399
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002400 /**
2401 * The elevation gets set for the first time and the framework needs to be informed that
2402 * the surface layer gets created with the shadow size in mind.
2403 */
2404 private void initializeElevation() {
2405 // TODO(skuhne): Call setMaxElevation here accordingly after b/22668382 got fixed.
2406 mAllowUpdateElevation = false;
2407 updateElevation();
2408 }
2409
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002410 private void updateElevation() {
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002411 float elevation = 0;
2412 final boolean wasAdjustedForStack = mElevationAdjustedForStack;
2413 // Do not use a shadow when we are in resizing mode (mBackdropFrameRenderer not null)
2414 // since the shadow is bound to the content size and not the target size.
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002415 final int windowingMode =
2416 getResources().getConfiguration().windowConfiguration.getWindowingMode();
2417 if ((windowingMode == WINDOWING_MODE_FREEFORM) && !isResizing()) {
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002418 elevation = hasWindowFocus() ?
2419 DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
Jaewan Kim880eff62016-04-27 10:36:35 +09002420 // Add a maximum shadow height value to the top level view.
2421 // Note that pinned stack doesn't have focus
2422 // so maximum shadow height adjustment isn't needed.
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002423 // TODO(skuhne): Remove this if clause once b/22668382 got fixed.
Robert Carr232b5f82017-04-17 15:11:35 -07002424 if (!mAllowUpdateElevation) {
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002425 elevation = DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
2426 }
2427 // Convert the DP elevation into physical pixels.
2428 elevation = dipToPx(elevation);
2429 mElevationAdjustedForStack = true;
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002430 } else if (windowingMode == WINDOWING_MODE_PINNED) {
Robert Carr32bcb102018-01-29 15:03:23 -08002431 elevation = dipToPx(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP);
Robert Carr232b5f82017-04-17 15:11:35 -07002432 mElevationAdjustedForStack = true;
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002433 } else {
2434 mElevationAdjustedForStack = false;
2435 }
2436
2437 // Don't change the elevation if we didn't previously adjust it for the stack it was in
2438 // or it didn't change.
2439 if ((wasAdjustedForStack || mElevationAdjustedForStack)
2440 && getElevation() != elevation) {
Garfield Tanfbd8ea62018-10-16 17:09:49 -07002441 if (!isResizing()) {
2442 mWindow.setElevation(elevation);
2443 } else {
2444 // Just suppress the shadow when resizing, don't adjust surface insets because it'll
2445 // cause a flicker when drag resize for freeform window starts. #onContentDrawn()
2446 // will compensate the offset when passing to BackdropFrameRenderer.
2447 setElevation(elevation);
2448 }
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002449 }
2450 }
2451
Wale Ogunwale8cc5a742015-11-17 15:41:05 -08002452 boolean isShowingCaption() {
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002453 return mDecorCaptionView != null && mDecorCaptionView.isCaptionShowing();
Wale Ogunwale8cc5a742015-11-17 15:41:05 -08002454 }
2455
2456 int getCaptionHeight() {
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002457 return isShowingCaption() ? mDecorCaptionView.getCaptionHeight() : 0;
Wale Ogunwale8cc5a742015-11-17 15:41:05 -08002458 }
2459
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002460 /**
2461 * Converts a DIP measure into physical pixels.
2462 * @param dip The dip value.
2463 * @return Returns the number of pixels.
2464 */
2465 private float dipToPx(float dip) {
2466 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
2467 getResources().getDisplayMetrics());
2468 }
2469
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002470 /**
2471 * Provide an override of the caption background drawable.
2472 */
2473 void setUserCaptionBackgroundDrawable(Drawable drawable) {
2474 mUserCaptionBackgroundDrawable = drawable;
2475 if (mBackdropFrameRenderer != null) {
2476 mBackdropFrameRenderer.setUserCaptionBackgroundDrawable(drawable);
2477 }
2478 }
2479
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002480 private static String getTitleSuffix(WindowManager.LayoutParams params) {
2481 if (params == null) {
2482 return "";
2483 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002484 final String[] split = params.getTitle().toString().split("\\.");
2485 if (split.length > 0) {
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002486 return split[split.length - 1];
2487 } else {
2488 return "";
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002489 }
2490 }
2491
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002492 void updateLogTag(WindowManager.LayoutParams params) {
2493 mLogTag = TAG + "[" + getTitleSuffix(params) + "]";
2494 }
2495
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002496 private void updateAvailableWidth() {
2497 Resources res = getResources();
2498 mAvailableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
2499 res.getConfiguration().screenWidthDp, res.getDisplayMetrics());
2500 }
2501
Clara Bayarri75e09792015-07-29 16:20:40 +01002502 /**
2503 * @hide
2504 */
2505 @Override
Clara Bayarrifcd7e802016-03-10 12:58:18 +00002506 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list, int deviceId) {
Clara Bayarri75e09792015-07-29 16:20:40 +01002507 final PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false);
Michael Wright936f27c2017-04-11 23:23:42 +01002508 final Menu menu = st != null ? st.menu : null;
2509 if (!mWindow.isDestroyed() && mWindow.getCallback() != null) {
2510 mWindow.getCallback().onProvideKeyboardShortcuts(list, menu, deviceId);
Clara Bayarri75e09792015-07-29 16:20:40 +01002511 }
2512 }
2513
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002514 @Override
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08002515 public void dispatchPointerCaptureChanged(boolean hasCapture) {
2516 super.dispatchPointerCaptureChanged(hasCapture);
2517 if (!mWindow.isDestroyed() && mWindow.getCallback() != null) {
2518 mWindow.getCallback().onPointerCaptureChanged(hasCapture);
2519 }
2520 }
2521
2522 @Override
Phil Weaverf00cd142017-03-03 13:44:00 -08002523 public int getAccessibilityViewId() {
2524 return AccessibilityNodeInfo.ROOT_ITEM_ID;
2525 }
2526
2527 @Override
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002528 public String toString() {
2529 return "DecorView@" + Integer.toHexString(this.hashCode()) + "["
2530 + getTitleSuffix(mWindow.getAttributes()) + "]";
2531 }
2532
Wale Ogunwale8804af22015-11-17 09:18:15 -08002533 private static class ColorViewState {
2534 View view = null;
2535 int targetVisibility = View.INVISIBLE;
2536 boolean present = false;
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002537 boolean visible;
2538 int color;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002539
Jorim Jaggi30d64f32017-04-07 16:33:17 +02002540 final ColorViewAttributes attributes;
2541
2542 ColorViewState(ColorViewAttributes attributes) {
2543 this.attributes = attributes;
2544 }
2545 }
2546
2547 public static class ColorViewAttributes {
2548
Wale Ogunwale8804af22015-11-17 09:18:15 -08002549 final int id;
2550 final int systemUiHideFlag;
2551 final int translucentFlag;
2552 final int verticalGravity;
2553 final int horizontalGravity;
Adrian Roos85d202b2016-06-02 16:27:47 -07002554 final int seascapeGravity;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002555 final String transitionName;
2556 final int hideWindowFlag;
Tiger Huang4a7835f2019-11-06 00:07:56 +08002557 final @InternalInsetsType int insetsType;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002558
Jorim Jaggi30d64f32017-04-07 16:33:17 +02002559 private ColorViewAttributes(int systemUiHideFlag, int translucentFlag, int verticalGravity,
2560 int horizontalGravity, int seascapeGravity, String transitionName, int id,
Tiger Huang4a7835f2019-11-06 00:07:56 +08002561 int hideWindowFlag, @InternalInsetsType int insetsType) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08002562 this.id = id;
2563 this.systemUiHideFlag = systemUiHideFlag;
2564 this.translucentFlag = translucentFlag;
2565 this.verticalGravity = verticalGravity;
2566 this.horizontalGravity = horizontalGravity;
Adrian Roos85d202b2016-06-02 16:27:47 -07002567 this.seascapeGravity = seascapeGravity;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002568 this.transitionName = transitionName;
2569 this.hideWindowFlag = hideWindowFlag;
Tiger Huang4a7835f2019-11-06 00:07:56 +08002570 this.insetsType = insetsType;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002571 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +02002572
Tiger Huang4a7835f2019-11-06 00:07:56 +08002573 // TODO(b/118118435): remove after migration
Jorim Jaggi30d64f32017-04-07 16:33:17 +02002574 public boolean isPresent(int sysUiVis, int windowFlags, boolean force) {
2575 return (sysUiVis & systemUiHideFlag) == 0
2576 && (windowFlags & hideWindowFlag) == 0
2577 && ((windowFlags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
2578 || force);
2579 }
2580
Tiger Huang4a7835f2019-11-06 00:07:56 +08002581 public boolean isPresent(InsetsState state, int windowFlags, boolean force) {
2582 return (state == null || state.getSource(insetsType).isVisible())
2583 && ((windowFlags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 || force);
2584 }
2585
Jorim Jaggi30d64f32017-04-07 16:33:17 +02002586 public boolean isVisible(boolean present, int color, int windowFlags, boolean force) {
2587 return present
2588 && (color & Color.BLACK) != 0
2589 && ((windowFlags & translucentFlag) == 0 || force);
2590 }
2591
Tiger Huang4a7835f2019-11-06 00:07:56 +08002592 // TODO(b/118118435): remove after migration
Jorim Jaggi30d64f32017-04-07 16:33:17 +02002593 public boolean isVisible(int sysUiVis, int color, int windowFlags, boolean force) {
2594 final boolean present = isPresent(sysUiVis, windowFlags, force);
2595 return isVisible(present, color, windowFlags, force);
2596 }
Tiger Huang4a7835f2019-11-06 00:07:56 +08002597
2598 public boolean isVisible(InsetsState state, int color, int windowFlags, boolean force) {
2599 final boolean present = isPresent(state, windowFlags, force);
2600 return isVisible(present, color, windowFlags, force);
2601 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08002602 }
2603
2604 /**
2605 * Clears out internal references when the action mode is destroyed.
2606 */
2607 private class ActionModeCallback2Wrapper extends ActionMode.Callback2 {
2608 private final ActionMode.Callback mWrapped;
2609
2610 public ActionModeCallback2Wrapper(ActionMode.Callback wrapped) {
2611 mWrapped = wrapped;
2612 }
2613
2614 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
2615 return mWrapped.onCreateActionMode(mode, menu);
2616 }
2617
2618 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
2619 requestFitSystemWindows();
2620 return mWrapped.onPrepareActionMode(mode, menu);
2621 }
2622
2623 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
2624 return mWrapped.onActionItemClicked(mode, item);
2625 }
2626
2627 public void onDestroyActionMode(ActionMode mode) {
2628 mWrapped.onDestroyActionMode(mode);
2629 final boolean isMncApp = mContext.getApplicationInfo().targetSdkVersion
Jorim Jaggi8f5701b2016-04-04 18:36:02 -07002630 >= M;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002631 final boolean isPrimary;
2632 final boolean isFloating;
2633 if (isMncApp) {
2634 isPrimary = mode == mPrimaryActionMode;
2635 isFloating = mode == mFloatingActionMode;
2636 if (!isPrimary && mode.getType() == ActionMode.TYPE_PRIMARY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002637 Log.e(mLogTag, "Destroying unexpected ActionMode instance of TYPE_PRIMARY; "
Wale Ogunwale8804af22015-11-17 09:18:15 -08002638 + mode + " was not the current primary action mode! Expected "
2639 + mPrimaryActionMode);
2640 }
2641 if (!isFloating && mode.getType() == ActionMode.TYPE_FLOATING) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002642 Log.e(mLogTag, "Destroying unexpected ActionMode instance of TYPE_FLOATING; "
Wale Ogunwale8804af22015-11-17 09:18:15 -08002643 + mode + " was not the current floating action mode! Expected "
2644 + mFloatingActionMode);
2645 }
2646 } else {
2647 isPrimary = mode.getType() == ActionMode.TYPE_PRIMARY;
2648 isFloating = mode.getType() == ActionMode.TYPE_FLOATING;
2649 }
2650 if (isPrimary) {
2651 if (mPrimaryActionModePopup != null) {
2652 removeCallbacks(mShowPrimaryActionModePopup);
2653 }
2654 if (mPrimaryActionModeView != null) {
2655 endOnGoingFadeAnimation();
Andrii Kulian8d6ac262016-06-08 13:14:19 -07002656 // Store action mode view reference, so we can access it safely when animation
2657 // ends. mPrimaryActionModePopup is set together with mPrimaryActionModeView,
2658 // so no need to store reference to it in separate variable.
2659 final ActionBarContextView lastActionModeView = mPrimaryActionModeView;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002660 mFadeAnim = ObjectAnimator.ofFloat(mPrimaryActionModeView, View.ALPHA,
2661 1f, 0f);
2662 mFadeAnim.addListener(new Animator.AnimatorListener() {
Andrii Kulian8d6ac262016-06-08 13:14:19 -07002663
Wale Ogunwale8804af22015-11-17 09:18:15 -08002664 @Override
2665 public void onAnimationStart(Animator animation) {
2666
2667 }
2668
2669 @Override
2670 public void onAnimationEnd(Animator animation) {
Andrii Kulian8d6ac262016-06-08 13:14:19 -07002671 // If mPrimaryActionModeView has changed - it means that we've
2672 // cleared the content while preserving decor view. We don't
2673 // want to change the state of new instances accidentally here.
2674 if (lastActionModeView == mPrimaryActionModeView) {
2675 lastActionModeView.setVisibility(GONE);
2676 if (mPrimaryActionModePopup != null) {
2677 mPrimaryActionModePopup.dismiss();
2678 }
2679 lastActionModeView.killMode();
2680 mFadeAnim = null;
Adrian Roos27db0ca2019-05-29 16:12:09 +02002681 requestApplyInsets();
Wale Ogunwale8804af22015-11-17 09:18:15 -08002682 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08002683 }
2684
2685 @Override
2686 public void onAnimationCancel(Animator animation) {
2687
2688 }
2689
2690 @Override
2691 public void onAnimationRepeat(Animator animation) {
2692
2693 }
2694 });
2695 mFadeAnim.start();
2696 }
2697
2698 mPrimaryActionMode = null;
2699 } else if (isFloating) {
2700 cleanupFloatingActionModeViews();
2701 mFloatingActionMode = null;
2702 }
2703 if (mWindow.getCallback() != null && !mWindow.isDestroyed()) {
2704 try {
2705 mWindow.getCallback().onActionModeFinished(mode);
2706 } catch (AbstractMethodError ame) {
2707 // Older apps might not implement this callback method.
2708 }
2709 }
2710 requestFitSystemWindows();
2711 }
2712
2713 @Override
2714 public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
2715 if (mWrapped instanceof ActionMode.Callback2) {
2716 ((ActionMode.Callback2) mWrapped).onGetContentRect(mode, view, outRect);
2717 } else {
2718 super.onGetContentRect(mode, view, outRect);
2719 }
2720 }
2721 }
2722}