blob: 07002d78890819e648f8a518be7e263f57d813e4 [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;
Wale Ogunwale8804af22015-11-17 09:18:15 -080025import static android.view.View.MeasureSpec.AT_MOST;
26import static android.view.View.MeasureSpec.EXACTLY;
27import static android.view.View.MeasureSpec.getMode;
28import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
29import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
Filip Gruszczynski3dec0812015-12-09 08:42:41 -080030import static android.view.Window.DECOR_CAPTION_SHADE_DARK;
31import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT;
Wale Ogunwale8804af22015-11-17 09:18:15 -080032import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
33import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
Jorim Jaggi9f6798a2016-02-10 22:16:06 -080034import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
Jorim Jaggi65bff3e2016-02-08 19:17:07 -080035import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
Wale Ogunwale8804af22015-11-17 09:18:15 -080036import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
37import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
Wale Ogunwale0d7e9122015-11-17 10:45:06 -080038import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
39import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
Chong Zhangfea963e2016-08-15 17:14:16 -070040import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
Adrian Roos4c864592019-04-10 14:47:57 +020041
Clara Bayarri75e09792015-07-29 16:20:40 +010042import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
Wale Ogunwale8804af22015-11-17 09:18:15 -080043
John Reck32f140aa62018-10-04 15:08:24 -070044import android.animation.Animator;
45import android.animation.AnimatorListenerAdapter;
46import android.animation.ObjectAnimator;
47import android.annotation.Nullable;
48import android.annotation.TestApi;
Andrei Onea15884392019-03-22 17:28:11 +000049import android.annotation.UnsupportedAppUsage;
John Reck32f140aa62018-10-04 15:08:24 -070050import android.app.WindowConfiguration;
51import android.content.Context;
52import android.content.res.Configuration;
53import android.content.res.Resources;
54import android.graphics.Canvas;
55import android.graphics.Color;
Jorim Jaggia6aabac2019-03-11 14:23:16 -070056import android.graphics.Insets;
John Reck32f140aa62018-10-04 15:08:24 -070057import android.graphics.LinearGradient;
58import android.graphics.Outline;
59import android.graphics.Paint;
60import android.graphics.PixelFormat;
61import android.graphics.RecordingCanvas;
62import android.graphics.Rect;
63import android.graphics.Region;
64import android.graphics.Shader;
65import android.graphics.drawable.ColorDrawable;
66import android.graphics.drawable.Drawable;
67import android.graphics.drawable.InsetDrawable;
68import android.graphics.drawable.LayerDrawable;
69import android.util.DisplayMetrics;
70import android.util.Log;
71import android.util.Pair;
72import android.util.TypedValue;
73import android.view.ActionMode;
74import android.view.ContextThemeWrapper;
75import android.view.Gravity;
76import android.view.InputQueue;
77import android.view.KeyEvent;
78import android.view.KeyboardShortcutGroup;
79import android.view.LayoutInflater;
80import android.view.Menu;
81import android.view.MenuItem;
82import android.view.MotionEvent;
83import android.view.ThreadedRenderer;
84import android.view.View;
85import android.view.ViewGroup;
86import android.view.ViewOutlineProvider;
Jorim Jaggi6482df52019-06-26 17:35:32 +020087import android.view.ViewRootImpl;
John Reck32f140aa62018-10-04 15:08:24 -070088import android.view.ViewStub;
89import android.view.ViewTreeObserver;
90import android.view.Window;
91import android.view.WindowCallbacks;
92import android.view.WindowInsets;
93import android.view.WindowManager;
94import android.view.accessibility.AccessibilityEvent;
95import android.view.accessibility.AccessibilityManager;
96import android.view.accessibility.AccessibilityNodeInfo;
97import android.view.animation.AnimationUtils;
98import android.view.animation.Interpolator;
99import android.widget.FrameLayout;
100import android.widget.PopupWindow;
101
102import com.android.internal.R;
103import com.android.internal.policy.PhoneWindow.PanelFeatureState;
104import com.android.internal.policy.PhoneWindow.PhoneWindowMenuCallback;
105import com.android.internal.view.FloatingActionMode;
106import com.android.internal.view.RootViewSurfaceTaker;
107import com.android.internal.view.StandaloneActionMode;
108import com.android.internal.view.menu.ContextMenuBuilder;
109import com.android.internal.view.menu.MenuHelper;
110import com.android.internal.widget.ActionBarContextView;
111import com.android.internal.widget.BackgroundFallback;
112import com.android.internal.widget.DecorCaptionView;
113import com.android.internal.widget.FloatingToolbar;
114
115import java.util.List;
116
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -0800117/** @hide */
118public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800119 private static final String TAG = "DecorView";
120
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -0800121 private static final boolean DEBUG_MEASURE = false;
122
Wale Ogunwale8804af22015-11-17 09:18:15 -0800123 private static final boolean SWEEP_OPEN_MENU = false;
124
Wale Ogunwale2b547c32015-11-18 10:33:22 -0800125 // The height of a window which has focus in DIP.
126 private final static int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20;
127 // The height of a window which has not in DIP.
128 private final static int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;
129
Adrian Roosc3f77562019-05-15 19:38:49 +0200130 private static final int SCRIM_LIGHT = 0xe6ffffff; // 90% white
Adrian Roos4c864592019-04-10 14:47:57 +0200131
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200132 public static final ColorViewAttributes STATUS_BAR_COLOR_VIEW_ATTRIBUTES =
133 new ColorViewAttributes(SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
134 Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
135 Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
136 com.android.internal.R.id.statusBarBackground,
137 FLAG_FULLSCREEN);
138
139 public static final ColorViewAttributes NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES =
140 new ColorViewAttributes(
141 SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
142 Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
143 Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
144 com.android.internal.R.id.navigationBarBackground,
145 0 /* hideWindowFlag */);
146
Winson Chung4d8681f2017-05-23 16:22:08 -0700147 // This is used to workaround an issue where the PiP shadow can be transparent if the window
148 // background is transparent
149 private static final ViewOutlineProvider PIP_OUTLINE_PROVIDER = new ViewOutlineProvider() {
150 @Override
151 public void getOutline(View view, Outline outline) {
152 outline.setRect(0, 0, view.getWidth(), view.getHeight());
153 outline.setAlpha(1f);
154 }
155 };
156
Wale Ogunwale2b547c32015-11-18 10:33:22 -0800157 // Cludge to address b/22668382: Set the shadow size to the maximum so that the layer
158 // size calculation takes the shadow size into account. We set the elevation currently
159 // to max until the first layout command has been executed.
160 private boolean mAllowUpdateElevation = false;
161
162 private boolean mElevationAdjustedForStack = false;
163
Winson Chung4d8681f2017-05-23 16:22:08 -0700164 // Keeps track of the picture-in-picture mode for the view shadow
165 private boolean mIsInPictureInPictureMode;
166
167 // Stores the previous outline provider prior to applying PIP_OUTLINE_PROVIDER
168 private ViewOutlineProvider mLastOutlineProvider;
169
Wale Ogunwale8804af22015-11-17 09:18:15 -0800170 int mDefaultOpacity = PixelFormat.OPAQUE;
171
172 /** The feature ID of the panel, or -1 if this is the application's DecorView */
173 private final int mFeatureId;
174
175 private final Rect mDrawingBounds = new Rect();
176
177 private final Rect mBackgroundPadding = new Rect();
178
179 private final Rect mFramePadding = new Rect();
180
181 private final Rect mFrameOffsets = new Rect();
182
Wale Ogunwale62a91d62015-11-18 11:44:10 -0800183 private boolean mHasCaption = false;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800184
185 private boolean mChanging;
186
187 private Drawable mMenuBackground;
188 private boolean mWatchingForMenu;
189 private int mDownY;
190
191 ActionMode mPrimaryActionMode;
192 private ActionMode mFloatingActionMode;
193 private ActionBarContextView mPrimaryActionModeView;
194 private PopupWindow mPrimaryActionModePopup;
195 private Runnable mShowPrimaryActionModePopup;
196 private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener;
197 private View mFloatingActionModeOriginatingView;
198 private FloatingToolbar mFloatingToolbar;
199 private ObjectAnimator mFadeAnim;
200
201 // View added at runtime to draw under the status bar area
202 private View mStatusGuard;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800203
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200204 private final ColorViewState mStatusColorViewState =
205 new ColorViewState(STATUS_BAR_COLOR_VIEW_ATTRIBUTES);
206 private final ColorViewState mNavigationColorViewState =
207 new ColorViewState(NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800208
209 private final Interpolator mShowInterpolator;
210 private final Interpolator mHideInterpolator;
211 private final int mBarEnterExitDuration;
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700212 final boolean mForceWindowDrawsBarBackgrounds;
213 private final int mSemiTransparentBarColor;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800214
215 private final BackgroundFallback mBackgroundFallback = new BackgroundFallback();
216
217 private int mLastTopInset = 0;
Andrei Onea15884392019-03-22 17:28:11 +0000218 @UnsupportedAppUsage
Wale Ogunwale8804af22015-11-17 09:18:15 -0800219 private int mLastBottomInset = 0;
Andrei Onea15884392019-03-22 17:28:11 +0000220 @UnsupportedAppUsage
Wale Ogunwale8804af22015-11-17 09:18:15 -0800221 private int mLastRightInset = 0;
Andrei Onea15884392019-03-22 17:28:11 +0000222 @UnsupportedAppUsage
Adrian Roos85d202b2016-06-02 16:27:47 -0700223 private int mLastLeftInset = 0;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800224 private boolean mLastHasTopStableInset = false;
225 private boolean mLastHasBottomStableInset = false;
226 private boolean mLastHasRightStableInset = false;
Adrian Roos85d202b2016-06-02 16:27:47 -0700227 private boolean mLastHasLeftStableInset = false;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800228 private int mLastWindowFlags = 0;
Brad Stenninge0573692019-03-11 13:52:46 -0700229 private boolean mLastShouldAlwaysConsumeSystemBars = false;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800230
231 private int mRootScrollY = 0;
232
Andrei Onea15884392019-03-22 17:28:11 +0000233 @UnsupportedAppUsage
Wale Ogunwale8804af22015-11-17 09:18:15 -0800234 private PhoneWindow mWindow;
235
236 ViewGroup mContentRoot;
237
238 private Rect mTempRect;
239 private Rect mOutsets = new Rect();
240
Wale Ogunwale62a91d62015-11-18 11:44:10 -0800241 // This is the caption view for the window, containing the caption and window control
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800242 // buttons. The visibility of this decor depends on the workspace and the window type.
243 // If the window type does not require such a view, this member might be null.
Garfield Tan3b9613c2018-12-26 17:08:51 -0800244 private DecorCaptionView mDecorCaptionView;
Wale Ogunwale0d7e9122015-11-17 10:45:06 -0800245
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -0800246 private boolean mWindowResizeCallbacksAdded = false;
Chong Zhangd3fd96c2016-02-08 18:25:24 -0800247 private Drawable.Callback mLastBackgroundDrawableCb = null;
Filip Gruszczynski3dec0812015-12-09 08:42:41 -0800248 private BackdropFrameRenderer mBackdropFrameRenderer = null;
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700249 private Drawable mOriginalBackgroundDrawable;
250 private Drawable mLastOriginalBackgroundDrawable;
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -0800251 private Drawable mResizingBackgroundDrawable;
252 private Drawable mCaptionBackgroundDrawable;
Filip Gruszczynski3dec0812015-12-09 08:42:41 -0800253 private Drawable mUserCaptionBackgroundDrawable;
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -0800254
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800255 private float mAvailableWidth;
256
257 String mLogTag = TAG;
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800258 private final Rect mFloatingInsets = new Rect();
259 private boolean mApplyFloatingVerticalInsets = false;
260 private boolean mApplyFloatingHorizontalInsets = false;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800261
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700262 private int mResizeMode = RESIZE_MODE_INVALID;
263 private final int mResizeShadowSize;
264 private final Paint mVerticalResizeShadowPaint = new Paint();
265 private final Paint mHorizontalResizeShadowPaint = new Paint();
Jorim Jaggi86d30ff2019-06-11 17:54:07 +0200266 private final Paint mLegacyNavigationBarBackgroundPaint = new Paint();
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700267 private Insets mBackgroundInsets = Insets.NONE;
268 private Insets mLastBackgroundInsets = Insets.NONE;
Jorim Jaggi86d30ff2019-06-11 17:54:07 +0200269 private boolean mDrawLegacyNavigationBarBackground;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700270
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800271 DecorView(Context context, int featureId, PhoneWindow window,
272 WindowManager.LayoutParams params) {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800273 super(context);
274 mFeatureId = featureId;
275
276 mShowInterpolator = AnimationUtils.loadInterpolator(context,
277 android.R.interpolator.linear_out_slow_in);
278 mHideInterpolator = AnimationUtils.loadInterpolator(context,
279 android.R.interpolator.fast_out_linear_in);
280
281 mBarEnterExitDuration = context.getResources().getInteger(
282 R.integer.dock_enter_exit_duration);
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700283 mForceWindowDrawsBarBackgrounds = context.getResources().getBoolean(
Jorim Jaggi8f5701b2016-04-04 18:36:02 -0700284 R.bool.config_forceWindowDrawsStatusBarBackground)
285 && context.getApplicationInfo().targetSdkVersion >= N;
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700286 mSemiTransparentBarColor = context.getResources().getColor(
Jorim Jaggi4fa78922015-11-30 17:13:56 -0800287 R.color.system_bar_background_semi_transparent, null /* theme */);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800288
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800289 updateAvailableWidth();
290
Wale Ogunwale8804af22015-11-17 09:18:15 -0800291 setWindow(window);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800292
293 updateLogTag(params);
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700294
295 mResizeShadowSize = context.getResources().getDimensionPixelSize(
296 R.dimen.resize_shadow_size);
297 initResizingPaints();
Jorim Jaggi86d30ff2019-06-11 17:54:07 +0200298
299 mLegacyNavigationBarBackgroundPaint.setColor(Color.BLACK);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800300 }
301
Nader Jawad56c68bc2018-04-24 17:08:51 -0700302 void setBackgroundFallback(@Nullable Drawable fallbackDrawable) {
303 mBackgroundFallback.setDrawable(fallbackDrawable);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800304 setWillNotDraw(getBackground() == null && !mBackgroundFallback.hasFallback());
305 }
306
Nader Jawad56c68bc2018-04-24 17:08:51 -0700307 @TestApi
308 public @Nullable Drawable getBackgroundFallback() {
309 return mBackgroundFallback.getDrawable();
310 }
311
Wale Ogunwale8804af22015-11-17 09:18:15 -0800312 @Override
Chris Craik867b8122016-05-05 16:19:22 -0700313 public boolean gatherTransparentRegion(Region region) {
314 boolean statusOpaque = gatherTransparentRegion(mStatusColorViewState, region);
315 boolean navOpaque = gatherTransparentRegion(mNavigationColorViewState, region);
316 boolean decorOpaque = super.gatherTransparentRegion(region);
317
318 // combine bools after computation, so each method above always executes
319 return statusOpaque || navOpaque || decorOpaque;
320 }
321
322 boolean gatherTransparentRegion(ColorViewState colorViewState, Region region) {
323 if (colorViewState.view != null && colorViewState.visible && isResizing()) {
324 // If a visible ColorViewState is in a resizing host DecorView, forcibly register its
325 // opaque area, since it's drawn by a different root RenderNode. It would otherwise be
326 // rejected by ViewGroup#gatherTransparentRegion() for the view not being VISIBLE.
327 return colorViewState.view.gatherTransparentRegion(region);
328 }
329 return false; // no opaque area added
330 }
331
332 @Override
Wale Ogunwale8804af22015-11-17 09:18:15 -0800333 public void onDraw(Canvas c) {
334 super.onDraw(c);
Jorim Jaggi853d17d2017-05-19 14:53:55 +0200335
Adrian Roos786ea782018-04-30 16:05:00 +0200336 mBackgroundFallback.draw(this, mContentRoot, c, mWindow.mContentParent,
337 mStatusColorViewState.view, mNavigationColorViewState.view);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800338 }
339
340 @Override
341 public boolean dispatchKeyEvent(KeyEvent event) {
342 final int keyCode = event.getKeyCode();
343 final int action = event.getAction();
344 final boolean isDown = action == KeyEvent.ACTION_DOWN;
345
346 if (isDown && (event.getRepeatCount() == 0)) {
347 // First handle chording of panel key: if a panel key is held
348 // but not released, try to execute a shortcut in it.
349 if ((mWindow.mPanelChordingKey > 0) && (mWindow.mPanelChordingKey != keyCode)) {
350 boolean handled = dispatchKeyShortcutEvent(event);
351 if (handled) {
352 return true;
353 }
354 }
355
356 // If a panel is open, perform a shortcut on it without the
357 // chorded panel key
358 if ((mWindow.mPreparedPanel != null) && mWindow.mPreparedPanel.isOpen) {
359 if (mWindow.performPanelShortcut(mWindow.mPreparedPanel, keyCode, event, 0)) {
360 return true;
361 }
362 }
363 }
364
365 if (!mWindow.isDestroyed()) {
366 final Window.Callback cb = mWindow.getCallback();
367 final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
368 : super.dispatchKeyEvent(event);
369 if (handled) {
370 return true;
371 }
372 }
373
374 return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event)
375 : mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
376 }
377
378 @Override
379 public boolean dispatchKeyShortcutEvent(KeyEvent ev) {
380 // If the panel is already prepared, then perform the shortcut using it.
381 boolean handled;
382 if (mWindow.mPreparedPanel != null) {
383 handled = mWindow.performPanelShortcut(mWindow.mPreparedPanel, ev.getKeyCode(), ev,
384 Menu.FLAG_PERFORM_NO_CLOSE);
385 if (handled) {
386 if (mWindow.mPreparedPanel != null) {
387 mWindow.mPreparedPanel.isHandled = true;
388 }
389 return true;
390 }
391 }
392
393 // Shortcut not handled by the panel. Dispatch to the view hierarchy.
394 final Window.Callback cb = mWindow.getCallback();
395 handled = cb != null && !mWindow.isDestroyed() && mFeatureId < 0
396 ? cb.dispatchKeyShortcutEvent(ev) : super.dispatchKeyShortcutEvent(ev);
397 if (handled) {
398 return true;
399 }
400
401 // If the panel is not prepared, then we may be trying to handle a shortcut key
402 // combination such as Control+C. Temporarily prepare the panel then mark it
403 // unprepared again when finished to ensure that the panel will again be prepared
404 // the next time it is shown for real.
405 PhoneWindow.PanelFeatureState st =
406 mWindow.getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
407 if (st != null && mWindow.mPreparedPanel == null) {
408 mWindow.preparePanel(st, ev);
409 handled = mWindow.performPanelShortcut(st, ev.getKeyCode(), ev,
410 Menu.FLAG_PERFORM_NO_CLOSE);
411 st.isPrepared = false;
412 if (handled) {
413 return true;
414 }
415 }
416 return false;
417 }
418
419 @Override
420 public boolean dispatchTouchEvent(MotionEvent ev) {
421 final Window.Callback cb = mWindow.getCallback();
422 return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
423 ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
424 }
425
426 @Override
427 public boolean dispatchTrackballEvent(MotionEvent ev) {
428 final Window.Callback cb = mWindow.getCallback();
429 return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
430 ? cb.dispatchTrackballEvent(ev) : super.dispatchTrackballEvent(ev);
431 }
432
433 @Override
434 public boolean dispatchGenericMotionEvent(MotionEvent ev) {
435 final Window.Callback cb = mWindow.getCallback();
436 return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
437 ? cb.dispatchGenericMotionEvent(ev) : super.dispatchGenericMotionEvent(ev);
438 }
439
440 public boolean superDispatchKeyEvent(KeyEvent event) {
441 // Give priority to closing action modes if applicable.
442 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
443 final int action = event.getAction();
444 // Back cancels action modes first.
445 if (mPrimaryActionMode != null) {
446 if (action == KeyEvent.ACTION_UP) {
447 mPrimaryActionMode.finish();
448 }
449 return true;
450 }
451 }
452
Evan Rosky5e29c072017-06-02 17:31:22 -0700453 if (super.dispatchKeyEvent(event)) {
454 return true;
455 }
456
Evan Roskycd80e612018-05-17 17:46:09 -0700457 return (getViewRootImpl() != null) && getViewRootImpl().dispatchUnhandledKeyEvent(event);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800458 }
459
460 public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
461 return super.dispatchKeyShortcutEvent(event);
462 }
463
464 public boolean superDispatchTouchEvent(MotionEvent event) {
465 return super.dispatchTouchEvent(event);
466 }
467
468 public boolean superDispatchTrackballEvent(MotionEvent event) {
469 return super.dispatchTrackballEvent(event);
470 }
471
472 public boolean superDispatchGenericMotionEvent(MotionEvent event) {
473 return super.dispatchGenericMotionEvent(event);
474 }
475
476 @Override
477 public boolean onTouchEvent(MotionEvent event) {
478 return onInterceptTouchEvent(event);
479 }
480
481 private boolean isOutOfInnerBounds(int x, int y) {
482 return x < 0 || y < 0 || x > getWidth() || y > getHeight();
483 }
484
485 private boolean isOutOfBounds(int x, int y) {
486 return x < -5 || y < -5 || x > (getWidth() + 5)
487 || y > (getHeight() + 5);
488 }
489
490 @Override
491 public boolean onInterceptTouchEvent(MotionEvent event) {
492 int action = event.getAction();
Wale Ogunwale62a91d62015-11-18 11:44:10 -0800493 if (mHasCaption && isShowingCaption()) {
494 // Don't dispatch ACTION_DOWN to the captionr if the window is resizable and the event
495 // was (starting) outside the window. Window resizing events should be handled by
496 // WindowManager.
Wale Ogunwale8804af22015-11-17 09:18:15 -0800497 // TODO: Investigate how to handle the outside touch in window manager
498 // without generating these events.
499 // Currently we receive these because we need to enlarge the window's
500 // touch region so that the monitor channel receives the events
501 // in the outside touch area.
502 if (action == MotionEvent.ACTION_DOWN) {
503 final int x = (int) event.getX();
504 final int y = (int) event.getY();
505 if (isOutOfInnerBounds(x, y)) {
506 return true;
507 }
508 }
509 }
510
511 if (mFeatureId >= 0) {
512 if (action == MotionEvent.ACTION_DOWN) {
513 int x = (int)event.getX();
514 int y = (int)event.getY();
515 if (isOutOfBounds(x, y)) {
516 mWindow.closePanel(mFeatureId);
517 return true;
518 }
519 }
520 }
521
522 if (!SWEEP_OPEN_MENU) {
523 return false;
524 }
525
526 if (mFeatureId >= 0) {
527 if (action == MotionEvent.ACTION_DOWN) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800528 Log.i(mLogTag, "Watchiing!");
Wale Ogunwale8804af22015-11-17 09:18:15 -0800529 mWatchingForMenu = true;
530 mDownY = (int) event.getY();
531 return false;
532 }
533
534 if (!mWatchingForMenu) {
535 return false;
536 }
537
538 int y = (int)event.getY();
539 if (action == MotionEvent.ACTION_MOVE) {
540 if (y > (mDownY+30)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800541 Log.i(mLogTag, "Closing!");
Wale Ogunwale8804af22015-11-17 09:18:15 -0800542 mWindow.closePanel(mFeatureId);
543 mWatchingForMenu = false;
544 return true;
545 }
546 } else if (action == MotionEvent.ACTION_UP) {
547 mWatchingForMenu = false;
548 }
549
550 return false;
551 }
552
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800553 //Log.i(mLogTag, "Intercept: action=" + action + " y=" + event.getY()
Wale Ogunwale8804af22015-11-17 09:18:15 -0800554 // + " (in " + getHeight() + ")");
555
556 if (action == MotionEvent.ACTION_DOWN) {
557 int y = (int)event.getY();
558 if (y >= (getHeight()-5) && !mWindow.hasChildren()) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800559 Log.i(mLogTag, "Watching!");
Wale Ogunwale8804af22015-11-17 09:18:15 -0800560 mWatchingForMenu = true;
561 }
562 return false;
563 }
564
565 if (!mWatchingForMenu) {
566 return false;
567 }
568
569 int y = (int)event.getY();
570 if (action == MotionEvent.ACTION_MOVE) {
571 if (y < (getHeight()-30)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800572 Log.i(mLogTag, "Opening!");
Wale Ogunwale8804af22015-11-17 09:18:15 -0800573 mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, new KeyEvent(
574 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
575 mWatchingForMenu = false;
576 return true;
577 }
578 } else if (action == MotionEvent.ACTION_UP) {
579 mWatchingForMenu = false;
580 }
581
582 return false;
583 }
584
585 @Override
586 public void sendAccessibilityEvent(int eventType) {
587 if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
588 return;
589 }
590
591 // if we are showing a feature that should be announced and one child
592 // make this child the event source since this is the feature itself
593 // otherwise the callback will take over and announce its client
594 if ((mFeatureId == Window.FEATURE_OPTIONS_PANEL ||
595 mFeatureId == Window.FEATURE_CONTEXT_MENU ||
596 mFeatureId == Window.FEATURE_PROGRESS ||
597 mFeatureId == Window.FEATURE_INDETERMINATE_PROGRESS)
598 && getChildCount() == 1) {
599 getChildAt(0).sendAccessibilityEvent(eventType);
600 } else {
601 super.sendAccessibilityEvent(eventType);
602 }
603 }
604
605 @Override
606 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
607 final Window.Callback cb = mWindow.getCallback();
608 if (cb != null && !mWindow.isDestroyed()) {
609 if (cb.dispatchPopulateAccessibilityEvent(event)) {
610 return true;
611 }
612 }
613 return super.dispatchPopulateAccessibilityEventInternal(event);
614 }
615
616 @Override
617 protected boolean setFrame(int l, int t, int r, int b) {
618 boolean changed = super.setFrame(l, t, r, b);
619 if (changed) {
620 final Rect drawingBounds = mDrawingBounds;
621 getDrawingRect(drawingBounds);
622
623 Drawable fg = getForeground();
624 if (fg != null) {
625 final Rect frameOffsets = mFrameOffsets;
626 drawingBounds.left += frameOffsets.left;
627 drawingBounds.top += frameOffsets.top;
628 drawingBounds.right -= frameOffsets.right;
629 drawingBounds.bottom -= frameOffsets.bottom;
630 fg.setBounds(drawingBounds);
631 final Rect framePadding = mFramePadding;
632 drawingBounds.left += framePadding.left - frameOffsets.left;
633 drawingBounds.top += framePadding.top - frameOffsets.top;
634 drawingBounds.right -= framePadding.right - frameOffsets.right;
635 drawingBounds.bottom -= framePadding.bottom - frameOffsets.bottom;
636 }
637
Jorim Jaggi24cf50f2019-04-09 15:16:23 +0200638 // Need to call super here as we pretend to be having the original background.
639 Drawable bg = super.getBackground();
Wale Ogunwale8804af22015-11-17 09:18:15 -0800640 if (bg != null) {
641 bg.setBounds(drawingBounds);
642 }
643
644 if (SWEEP_OPEN_MENU) {
645 if (mMenuBackground == null && mFeatureId < 0
646 && mWindow.getAttributes().height
647 == WindowManager.LayoutParams.MATCH_PARENT) {
648 mMenuBackground = getContext().getDrawable(
649 R.drawable.menu_background);
650 }
651 if (mMenuBackground != null) {
652 mMenuBackground.setBounds(drawingBounds.left,
653 drawingBounds.bottom-6, drawingBounds.right,
654 drawingBounds.bottom+20);
655 }
656 }
657 }
658 return changed;
659 }
660
661 @Override
662 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
663 final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800664 final boolean isPortrait =
665 getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800666
667 final int widthMode = getMode(widthMeasureSpec);
668 final int heightMode = getMode(heightMeasureSpec);
669
670 boolean fixedWidth = false;
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800671 mApplyFloatingHorizontalInsets = false;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800672 if (widthMode == AT_MOST) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800673 final TypedValue tvw = isPortrait ? mWindow.mFixedWidthMinor : mWindow.mFixedWidthMajor;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800674 if (tvw != null && tvw.type != TypedValue.TYPE_NULL) {
675 final int w;
676 if (tvw.type == TypedValue.TYPE_DIMENSION) {
677 w = (int) tvw.getDimension(metrics);
678 } else if (tvw.type == TypedValue.TYPE_FRACTION) {
679 w = (int) tvw.getFraction(metrics.widthPixels, metrics.widthPixels);
680 } else {
681 w = 0;
682 }
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -0800683 if (DEBUG_MEASURE) Log.d(mLogTag, "Fixed width: " + w);
Jorim Jaggiffd04902016-02-23 19:20:59 -0500684 final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800685 if (w > 0) {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800686 widthMeasureSpec = MeasureSpec.makeMeasureSpec(
687 Math.min(w, widthSize), EXACTLY);
688 fixedWidth = true;
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800689 } else {
690 widthMeasureSpec = MeasureSpec.makeMeasureSpec(
Jorim Jaggiffd04902016-02-23 19:20:59 -0500691 widthSize - mFloatingInsets.left - mFloatingInsets.right,
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800692 AT_MOST);
693 mApplyFloatingHorizontalInsets = true;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800694 }
695 }
696 }
697
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800698 mApplyFloatingVerticalInsets = false;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800699 if (heightMode == AT_MOST) {
700 final TypedValue tvh = isPortrait ? mWindow.mFixedHeightMajor
701 : mWindow.mFixedHeightMinor;
702 if (tvh != null && tvh.type != TypedValue.TYPE_NULL) {
703 final int h;
704 if (tvh.type == TypedValue.TYPE_DIMENSION) {
705 h = (int) tvh.getDimension(metrics);
706 } else if (tvh.type == TypedValue.TYPE_FRACTION) {
707 h = (int) tvh.getFraction(metrics.heightPixels, metrics.heightPixels);
708 } else {
709 h = 0;
710 }
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -0800711 if (DEBUG_MEASURE) Log.d(mLogTag, "Fixed height: " + h);
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800712 final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800713 if (h > 0) {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800714 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
715 Math.min(h, heightSize), EXACTLY);
Jorim Jaggi65bff3e2016-02-08 19:17:07 -0800716 } else if ((mWindow.getAttributes().flags & FLAG_LAYOUT_IN_SCREEN) == 0) {
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800717 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
718 heightSize - mFloatingInsets.top - mFloatingInsets.bottom, AT_MOST);
719 mApplyFloatingVerticalInsets = true;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800720 }
721 }
722 }
723
724 getOutsets(mOutsets);
725 if (mOutsets.top > 0 || mOutsets.bottom > 0) {
726 int mode = MeasureSpec.getMode(heightMeasureSpec);
727 if (mode != MeasureSpec.UNSPECIFIED) {
728 int height = MeasureSpec.getSize(heightMeasureSpec);
729 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
730 height + mOutsets.top + mOutsets.bottom, mode);
731 }
732 }
733 if (mOutsets.left > 0 || mOutsets.right > 0) {
734 int mode = MeasureSpec.getMode(widthMeasureSpec);
735 if (mode != MeasureSpec.UNSPECIFIED) {
736 int width = MeasureSpec.getSize(widthMeasureSpec);
737 widthMeasureSpec = MeasureSpec.makeMeasureSpec(
738 width + mOutsets.left + mOutsets.right, mode);
739 }
740 }
741
742 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
743
744 int width = getMeasuredWidth();
745 boolean measure = false;
746
747 widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
748
749 if (!fixedWidth && widthMode == AT_MOST) {
750 final TypedValue tv = isPortrait ? mWindow.mMinWidthMinor : mWindow.mMinWidthMajor;
751 if (tv.type != TypedValue.TYPE_NULL) {
752 final int min;
753 if (tv.type == TypedValue.TYPE_DIMENSION) {
754 min = (int)tv.getDimension(metrics);
755 } else if (tv.type == TypedValue.TYPE_FRACTION) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800756 min = (int)tv.getFraction(mAvailableWidth, mAvailableWidth);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800757 } else {
758 min = 0;
759 }
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -0800760 if (DEBUG_MEASURE) Log.d(mLogTag, "Adjust for min width: " + min + ", value::"
761 + tv.coerceToString() + ", mAvailableWidth=" + mAvailableWidth);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800762
763 if (width < min) {
764 widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
765 measure = true;
766 }
767 }
768 }
769
770 // TODO: Support height?
771
772 if (measure) {
773 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
774 }
775 }
776
777 @Override
778 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
779 super.onLayout(changed, left, top, right, bottom);
780 getOutsets(mOutsets);
781 if (mOutsets.left > 0) {
782 offsetLeftAndRight(-mOutsets.left);
783 }
784 if (mOutsets.top > 0) {
785 offsetTopAndBottom(-mOutsets.top);
786 }
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -0800787 if (mApplyFloatingVerticalInsets) {
788 offsetTopAndBottom(mFloatingInsets.top);
789 }
790 if (mApplyFloatingHorizontalInsets) {
791 offsetLeftAndRight(mFloatingInsets.left);
792 }
Wale Ogunwale2b547c32015-11-18 10:33:22 -0800793
794 // If the application changed its SystemUI metrics, we might also have to adapt
795 // our shadow elevation.
796 updateElevation();
797 mAllowUpdateElevation = true;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700798
Vinit Nayak0aa0f132019-09-12 18:15:21 -0700799 if (changed
800 && (mResizeMode == RESIZE_MODE_DOCKED_DIVIDER
801 || mDrawLegacyNavigationBarBackground)) {
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700802 getViewRootImpl().requestInvalidateRootRenderNode();
803 }
Wale Ogunwale8804af22015-11-17 09:18:15 -0800804 }
805
806 @Override
807 public void draw(Canvas canvas) {
808 super.draw(canvas);
809
810 if (mMenuBackground != null) {
811 mMenuBackground.draw(canvas);
812 }
813 }
814
815 @Override
816 public boolean showContextMenuForChild(View originalView) {
Oren Blasberg23e282d2016-04-20 13:43:45 -0700817 return showContextMenuForChildInternal(originalView, Float.NaN, Float.NaN);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800818 }
819
820 @Override
821 public boolean showContextMenuForChild(View originalView, float x, float y) {
Oren Blasberg23e282d2016-04-20 13:43:45 -0700822 return showContextMenuForChildInternal(originalView, x, y);
Alan Viverette021627e2015-11-25 14:22:00 -0500823 }
824
825 private boolean showContextMenuForChildInternal(View originalView,
Oren Blasberg23e282d2016-04-20 13:43:45 -0700826 float x, float y) {
Alan Viverette021627e2015-11-25 14:22:00 -0500827 // Only allow one context menu at a time.
828 if (mWindow.mContextMenuHelper != null) {
829 mWindow.mContextMenuHelper.dismiss();
830 mWindow.mContextMenuHelper = null;
831 }
832
833 // Reuse the context menu builder.
Alan Viverette77fb85e2015-12-14 11:42:44 -0500834 final PhoneWindowMenuCallback callback = mWindow.mContextMenuCallback;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800835 if (mWindow.mContextMenu == null) {
836 mWindow.mContextMenu = new ContextMenuBuilder(getContext());
Alan Viverette77fb85e2015-12-14 11:42:44 -0500837 mWindow.mContextMenu.setCallback(callback);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800838 } else {
839 mWindow.mContextMenu.clearAll();
840 }
841
Alan Viverette021627e2015-11-25 14:22:00 -0500842 final MenuHelper helper;
Oren Blasberg23e282d2016-04-20 13:43:45 -0700843 final boolean isPopup = !Float.isNaN(x) && !Float.isNaN(y);
Alan Viverette021627e2015-11-25 14:22:00 -0500844 if (isPopup) {
845 helper = mWindow.mContextMenu.showPopup(getContext(), originalView, x, y);
846 } else {
847 helper = mWindow.mContextMenu.showDialog(originalView, originalView.getWindowToken());
Wale Ogunwale8804af22015-11-17 09:18:15 -0800848 }
Alan Viverette021627e2015-11-25 14:22:00 -0500849
Alan Viverette9084d222015-12-16 09:56:37 -0500850 if (helper != null) {
851 // If it's a dialog, the callback needs to handle showing
852 // sub-menus. Either way, the callback is required for propagating
853 // selection to Context.onContextMenuItemSelected().
854 callback.setShowDialogForSubmenu(!isPopup);
855 helper.setPresenterCallback(callback);
856 }
Alan Viverette021627e2015-11-25 14:22:00 -0500857
858 mWindow.mContextMenuHelper = helper;
Wale Ogunwale8804af22015-11-17 09:18:15 -0800859 return helper != null;
860 }
861
862 @Override
863 public ActionMode startActionModeForChild(View originalView,
864 ActionMode.Callback callback) {
865 return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
866 }
867
868 @Override
869 public ActionMode startActionModeForChild(
870 View child, ActionMode.Callback callback, int type) {
871 return startActionMode(child, callback, type);
872 }
873
874 @Override
875 public ActionMode startActionMode(ActionMode.Callback callback) {
876 return startActionMode(callback, ActionMode.TYPE_PRIMARY);
877 }
878
879 @Override
880 public ActionMode startActionMode(ActionMode.Callback callback, int type) {
881 return startActionMode(this, callback, type);
882 }
883
884 private ActionMode startActionMode(
885 View originatingView, ActionMode.Callback callback, int type) {
886 ActionMode.Callback2 wrappedCallback = new ActionModeCallback2Wrapper(callback);
887 ActionMode mode = null;
888 if (mWindow.getCallback() != null && !mWindow.isDestroyed()) {
889 try {
890 mode = mWindow.getCallback().onWindowStartingActionMode(wrappedCallback, type);
891 } catch (AbstractMethodError ame) {
892 // Older apps might not implement the typed version of this method.
893 if (type == ActionMode.TYPE_PRIMARY) {
894 try {
895 mode = mWindow.getCallback().onWindowStartingActionMode(
896 wrappedCallback);
897 } catch (AbstractMethodError ame2) {
898 // Older apps might not implement this callback method at all.
899 }
900 }
901 }
902 }
903 if (mode != null) {
904 if (mode.getType() == ActionMode.TYPE_PRIMARY) {
905 cleanupPrimaryActionMode();
906 mPrimaryActionMode = mode;
907 } else if (mode.getType() == ActionMode.TYPE_FLOATING) {
908 if (mFloatingActionMode != null) {
909 mFloatingActionMode.finish();
910 }
911 mFloatingActionMode = mode;
912 }
913 } else {
914 mode = createActionMode(type, wrappedCallback, originatingView);
915 if (mode != null && wrappedCallback.onCreateActionMode(mode, mode.getMenu())) {
916 setHandledActionMode(mode);
917 } else {
918 mode = null;
919 }
920 }
921 if (mode != null && mWindow.getCallback() != null && !mWindow.isDestroyed()) {
922 try {
923 mWindow.getCallback().onActionModeStarted(mode);
924 } catch (AbstractMethodError ame) {
925 // Older apps might not implement this callback method.
926 }
927 }
928 return mode;
929 }
930
931 private void cleanupPrimaryActionMode() {
932 if (mPrimaryActionMode != null) {
933 mPrimaryActionMode.finish();
934 mPrimaryActionMode = null;
935 }
936 if (mPrimaryActionModeView != null) {
937 mPrimaryActionModeView.killMode();
938 }
939 }
940
941 private void cleanupFloatingActionModeViews() {
942 if (mFloatingToolbar != null) {
943 mFloatingToolbar.dismiss();
944 mFloatingToolbar = null;
945 }
946 if (mFloatingActionModeOriginatingView != null) {
947 if (mFloatingToolbarPreDrawListener != null) {
948 mFloatingActionModeOriginatingView.getViewTreeObserver()
949 .removeOnPreDrawListener(mFloatingToolbarPreDrawListener);
950 mFloatingToolbarPreDrawListener = null;
951 }
952 mFloatingActionModeOriginatingView = null;
953 }
954 }
955
Wale Ogunwale62a91d62015-11-18 11:44:10 -0800956 void startChanging() {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800957 mChanging = true;
958 }
959
Wale Ogunwale62a91d62015-11-18 11:44:10 -0800960 void finishChanging() {
Wale Ogunwale8804af22015-11-17 09:18:15 -0800961 mChanging = false;
962 drawableChanged();
963 }
964
965 public void setWindowBackground(Drawable drawable) {
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700966 if (mOriginalBackgroundDrawable != drawable) {
967 mOriginalBackgroundDrawable = drawable;
968 updateBackgroundDrawable();
Wale Ogunwale8804af22015-11-17 09:18:15 -0800969 if (drawable != null) {
Jorim Jaggi8e879f12016-05-25 16:41:49 -0700970 mResizingBackgroundDrawable = enforceNonTranslucentBackground(drawable,
971 mWindow.isTranslucent() || mWindow.isShowingWallpaper());
Robert Carr692a5fe2016-05-19 14:11:15 -0700972 } else {
973 mResizingBackgroundDrawable = getResizingBackgroundDrawable(
Nader Jawad56c68bc2018-04-24 17:08:51 -0700974 mWindow.mBackgroundDrawable, mWindow.mBackgroundFallbackDrawable,
Jorim Jaggi8e879f12016-05-25 16:41:49 -0700975 mWindow.isTranslucent() || mWindow.isShowingWallpaper());
Robert Carr692a5fe2016-05-19 14:11:15 -0700976 }
977 if (mResizingBackgroundDrawable != null) {
978 mResizingBackgroundDrawable.getPadding(mBackgroundPadding);
Wale Ogunwale8804af22015-11-17 09:18:15 -0800979 } else {
980 mBackgroundPadding.setEmpty();
981 }
982 drawableChanged();
983 }
984 }
985
Jorim Jaggi24cf50f2019-04-09 15:16:23 +0200986 @Override
987 public void setBackgroundDrawable(Drawable background) {
Jorim Jaggi24cf50f2019-04-09 15:16:23 +0200988 // TODO: This should route through setWindowBackground, but late in the release to make this
989 // change.
990 if (mOriginalBackgroundDrawable != background) {
991 mOriginalBackgroundDrawable = background;
992 updateBackgroundDrawable();
Vadim Caen843f9de2019-07-24 16:24:33 +0200993 if (!View.sBrokenWindowBackground) {
994 drawableChanged();
995 }
Jorim Jaggi24cf50f2019-04-09 15:16:23 +0200996 }
997 }
998
Wale Ogunwale8804af22015-11-17 09:18:15 -0800999 public void setWindowFrame(Drawable drawable) {
1000 if (getForeground() != drawable) {
1001 setForeground(drawable);
1002 if (drawable != null) {
1003 drawable.getPadding(mFramePadding);
1004 } else {
1005 mFramePadding.setEmpty();
1006 }
1007 drawableChanged();
1008 }
1009 }
1010
1011 @Override
1012 public void onWindowSystemUiVisibilityChanged(int visible) {
1013 updateColorViews(null /* insets */, true /* animate */);
Garfield Tan3b9613c2018-12-26 17:08:51 -08001014 updateDecorCaptionStatus(getResources().getConfiguration());
Adrian Roos27db0ca2019-05-29 16:12:09 +02001015
1016 if (mStatusGuard != null && mStatusGuard.getVisibility() == VISIBLE) {
1017 updateStatusGuardColor();
1018 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001019 }
1020
1021 @Override
1022 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -08001023 final WindowManager.LayoutParams attrs = mWindow.getAttributes();
1024 mFloatingInsets.setEmpty();
Jorim Jaggi65bff3e2016-02-08 19:17:07 -08001025 if ((attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0) {
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -08001026 // For dialog windows we want to make sure they don't go over the status bar or nav bar.
1027 // We consume the system insets and we will reuse them later during the measure phase.
Jorim Jaggi65bff3e2016-02-08 19:17:07 -08001028 // We allow the app to ignore this and handle insets itself by using
1029 // FLAG_LAYOUT_IN_SCREEN.
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -08001030 if (attrs.height == WindowManager.LayoutParams.WRAP_CONTENT) {
1031 mFloatingInsets.top = insets.getSystemWindowInsetTop();
1032 mFloatingInsets.bottom = insets.getSystemWindowInsetBottom();
Adrian Roosf7b74262017-11-22 14:21:01 +01001033 insets = insets.inset(0, insets.getSystemWindowInsetTop(),
1034 0, insets.getSystemWindowInsetBottom());
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -08001035 }
1036 if (mWindow.getAttributes().width == WindowManager.LayoutParams.WRAP_CONTENT) {
1037 mFloatingInsets.left = insets.getSystemWindowInsetTop();
1038 mFloatingInsets.right = insets.getSystemWindowInsetBottom();
Adrian Roosf7b74262017-11-22 14:21:01 +01001039 insets = insets.inset(insets.getSystemWindowInsetLeft(), 0,
1040 insets.getSystemWindowInsetRight(), 0);
Filip Gruszczynskiadf7b5e2016-01-27 16:23:05 -08001041 }
1042 }
Adrian Roos60f59292018-08-24 16:29:06 +02001043 mFrameOffsets.set(insets.getSystemWindowInsetsAsRect());
Wale Ogunwale8804af22015-11-17 09:18:15 -08001044 insets = updateColorViews(insets, true /* animate */);
1045 insets = updateStatusGuard(insets);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001046 if (getForeground() != null) {
1047 drawableChanged();
1048 }
1049 return insets;
1050 }
1051
1052 @Override
1053 public boolean isTransitionGroup() {
1054 return false;
1055 }
1056
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001057 public static int getColorViewTopInset(int stableTop, int systemTop) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001058 return Math.min(stableTop, systemTop);
1059 }
1060
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001061 public static int getColorViewBottomInset(int stableBottom, int systemBottom) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001062 return Math.min(stableBottom, systemBottom);
1063 }
1064
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001065 public static int getColorViewRightInset(int stableRight, int systemRight) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001066 return Math.min(stableRight, systemRight);
1067 }
1068
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001069 public static int getColorViewLeftInset(int stableLeft, int systemLeft) {
Adrian Roos85d202b2016-06-02 16:27:47 -07001070 return Math.min(stableLeft, systemLeft);
1071 }
1072
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001073 public static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001074 return bottomInset == 0 && rightInset > 0;
1075 }
1076
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001077 public static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
Adrian Roos85d202b2016-06-02 16:27:47 -07001078 return bottomInset == 0 && leftInset > 0;
1079 }
1080
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001081 public static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
Adrian Roos85d202b2016-06-02 16:27:47 -07001082 return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset
1083 : isNavBarToLeftEdge(bottomInset, leftInset) ? leftInset : bottomInset;
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001084 }
1085
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001086 public static void getNavigationBarRect(int canvasWidth, int canvasHeight, Rect stableInsets,
Winson Chungffde2ea2019-06-17 17:19:13 -07001087 Rect contentInsets, Rect outRect, float scale) {
1088 final int bottomInset =
1089 (int) (getColorViewBottomInset(stableInsets.bottom, contentInsets.bottom) * scale);
1090 final int leftInset =
1091 (int) (getColorViewLeftInset(stableInsets.left, contentInsets.left) * scale);
1092 final int rightInset =
1093 (int) (getColorViewLeftInset(stableInsets.right, contentInsets.right) * scale);
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001094 final int size = getNavBarSize(bottomInset, rightInset, leftInset);
1095 if (isNavBarToRightEdge(bottomInset, rightInset)) {
1096 outRect.set(canvasWidth - size, 0, canvasWidth, canvasHeight);
1097 } else if (isNavBarToLeftEdge(bottomInset, leftInset)) {
1098 outRect.set(0, 0, size, canvasHeight);
1099 } else {
1100 outRect.set(0, canvasHeight - size, canvasWidth, canvasHeight);
1101 }
1102 }
1103
Wale Ogunwale8804af22015-11-17 09:18:15 -08001104 WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
1105 WindowManager.LayoutParams attrs = mWindow.getAttributes();
1106 int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
1107
Yohei Yukawa8f162c62018-01-10 13:18:09 -08001108 // IME is an exceptional floating window that requires color view.
1109 final boolean isImeWindow =
1110 mWindow.getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD;
1111 if (!mWindow.mIsFloating || isImeWindow) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001112 boolean disallowAnimate = !isLaidOut();
1113 disallowAnimate |= ((mLastWindowFlags ^ attrs.flags)
1114 & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
1115 mLastWindowFlags = attrs.flags;
1116
1117 if (insets != null) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001118 mLastTopInset = getColorViewTopInset(insets.getStableInsetTop(),
Wale Ogunwale8804af22015-11-17 09:18:15 -08001119 insets.getSystemWindowInsetTop());
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001120 mLastBottomInset = getColorViewBottomInset(insets.getStableInsetBottom(),
Wale Ogunwale8804af22015-11-17 09:18:15 -08001121 insets.getSystemWindowInsetBottom());
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001122 mLastRightInset = getColorViewRightInset(insets.getStableInsetRight(),
Wale Ogunwale8804af22015-11-17 09:18:15 -08001123 insets.getSystemWindowInsetRight());
Adrian Roos85d202b2016-06-02 16:27:47 -07001124 mLastLeftInset = getColorViewRightInset(insets.getStableInsetLeft(),
1125 insets.getSystemWindowInsetLeft());
Wale Ogunwale8804af22015-11-17 09:18:15 -08001126
1127 // Don't animate if the presence of stable insets has changed, because that
1128 // indicates that the window was either just added and received them for the
1129 // first time, or the window size or position has changed.
1130 boolean hasTopStableInset = insets.getStableInsetTop() != 0;
1131 disallowAnimate |= (hasTopStableInset != mLastHasTopStableInset);
1132 mLastHasTopStableInset = hasTopStableInset;
1133
1134 boolean hasBottomStableInset = insets.getStableInsetBottom() != 0;
1135 disallowAnimate |= (hasBottomStableInset != mLastHasBottomStableInset);
1136 mLastHasBottomStableInset = hasBottomStableInset;
1137
1138 boolean hasRightStableInset = insets.getStableInsetRight() != 0;
1139 disallowAnimate |= (hasRightStableInset != mLastHasRightStableInset);
1140 mLastHasRightStableInset = hasRightStableInset;
Adrian Roos85d202b2016-06-02 16:27:47 -07001141
1142 boolean hasLeftStableInset = insets.getStableInsetLeft() != 0;
1143 disallowAnimate |= (hasLeftStableInset != mLastHasLeftStableInset);
1144 mLastHasLeftStableInset = hasLeftStableInset;
1145
Brad Stenninge0573692019-03-11 13:52:46 -07001146 mLastShouldAlwaysConsumeSystemBars = insets.shouldAlwaysConsumeSystemBars();
Wale Ogunwale8804af22015-11-17 09:18:15 -08001147 }
1148
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001149 boolean navBarToRightEdge = isNavBarToRightEdge(mLastBottomInset, mLastRightInset);
Adrian Roos85d202b2016-06-02 16:27:47 -07001150 boolean navBarToLeftEdge = isNavBarToLeftEdge(mLastBottomInset, mLastLeftInset);
1151 int navBarSize = getNavBarSize(mLastBottomInset, mLastRightInset, mLastLeftInset);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001152 updateColorViewInt(mNavigationColorViewState, sysUiVisibility,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001153 calculateNavigationBarColor(), mWindow.mNavigationBarDividerColor, navBarSize,
Jason Monkea506c62017-09-01 12:40:06 -04001154 navBarToRightEdge || navBarToLeftEdge, navBarToLeftEdge,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001155 0 /* sideInset */, animate && !disallowAnimate,
1156 mForceWindowDrawsBarBackgrounds);
Jorim Jaggi6482df52019-06-26 17:35:32 +02001157 boolean oldDrawLegacy = mDrawLegacyNavigationBarBackground;
Jorim Jaggi86d30ff2019-06-11 17:54:07 +02001158 mDrawLegacyNavigationBarBackground = mNavigationColorViewState.visible
1159 && (mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0;
Jorim Jaggi6482df52019-06-26 17:35:32 +02001160 if (oldDrawLegacy != mDrawLegacyNavigationBarBackground) {
1161 ViewRootImpl vri = getViewRootImpl();
1162 if (vri != null) {
1163 vri.requestInvalidateRootRenderNode();
1164 }
1165 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001166
1167 boolean statusBarNeedsRightInset = navBarToRightEdge
1168 && mNavigationColorViewState.present;
Adrian Roos85d202b2016-06-02 16:27:47 -07001169 boolean statusBarNeedsLeftInset = navBarToLeftEdge
1170 && mNavigationColorViewState.present;
1171 int statusBarSideInset = statusBarNeedsRightInset ? mLastRightInset
1172 : statusBarNeedsLeftInset ? mLastLeftInset : 0;
Jorim Jaggi4fa78922015-11-30 17:13:56 -08001173 updateColorViewInt(mStatusColorViewState, sysUiVisibility,
Jason Monkea506c62017-09-01 12:40:06 -04001174 calculateStatusBarColor(), 0, mLastTopInset,
Adrian Roos85d202b2016-06-02 16:27:47 -07001175 false /* matchVertical */, statusBarNeedsLeftInset, statusBarSideInset,
1176 animate && !disallowAnimate,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001177 mForceWindowDrawsBarBackgrounds);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001178 }
1179
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001180 // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS or
1181 // mForceWindowDrawsBarBackgrounds, we still need to ensure that the rest of the view
1182 // hierarchy doesn't notice it, unless they've explicitly asked for it.
1183 //
1184 // Note: We don't need to check for IN_SCREEN or INSET_DECOR because unlike the status bar,
1185 // these flags wouldn't make the window draw behind the navigation bar, unless
1186 // LAYOUT_HIDE_NAVIGATION was set.
Adrian Roosfaba4062019-05-14 15:27:17 +02001187 boolean hideNavigation = (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001188 boolean forceConsumingNavBar = (mForceWindowDrawsBarBackgrounds
1189 && (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
Wale Ogunwale8804af22015-11-17 09:18:15 -08001190 && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
Adrian Roosfaba4062019-05-14 15:27:17 +02001191 && !hideNavigation)
1192 || (mLastShouldAlwaysConsumeSystemBars && hideNavigation);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001193
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001194 boolean consumingNavBar =
1195 ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
1196 && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
Adrian Roosfaba4062019-05-14 15:27:17 +02001197 && !hideNavigation)
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001198 || forceConsumingNavBar;
1199
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001200 // If we didn't request fullscreen layout, but we still got it because of the
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001201 // mForceWindowDrawsBarBackgrounds flag, also consume top inset.
Jorim Jaggi01d60d02019-05-07 17:10:42 +02001202 // If we should always consume system bars, only consume that if the app wanted to go to
1203 // fullscreen, as othrewise we can expect the app to handle it.
1204 boolean fullscreen = (sysUiVisibility & SYSTEM_UI_FLAG_FULLSCREEN) != 0
1205 || (attrs.flags & FLAG_FULLSCREEN) != 0;
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001206 boolean consumingStatusBar = (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == 0
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001207 && (attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0
1208 && (attrs.flags & FLAG_LAYOUT_INSET_DECOR) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001209 && mForceWindowDrawsBarBackgrounds
Brad Stenninge0573692019-03-11 13:52:46 -07001210 && mLastTopInset != 0
Jorim Jaggi01d60d02019-05-07 17:10:42 +02001211 || (mLastShouldAlwaysConsumeSystemBars && fullscreen);
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001212
1213 int consumedTop = consumingStatusBar ? mLastTopInset : 0;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001214 int consumedRight = consumingNavBar ? mLastRightInset : 0;
1215 int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
Adrian Roos85d202b2016-06-02 16:27:47 -07001216 int consumedLeft = consumingNavBar ? mLastLeftInset : 0;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001217
1218 if (mContentRoot != null
1219 && mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
1220 MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001221 if (lp.topMargin != consumedTop || lp.rightMargin != consumedRight
Adrian Roos85d202b2016-06-02 16:27:47 -07001222 || lp.bottomMargin != consumedBottom || lp.leftMargin != consumedLeft) {
Jorim Jaggi9f6798a2016-02-10 22:16:06 -08001223 lp.topMargin = consumedTop;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001224 lp.rightMargin = consumedRight;
1225 lp.bottomMargin = consumedBottom;
Adrian Roos85d202b2016-06-02 16:27:47 -07001226 lp.leftMargin = consumedLeft;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001227 mContentRoot.setLayoutParams(lp);
1228
1229 if (insets == null) {
1230 // The insets have changed, but we're not currently in the process
1231 // of dispatching them.
1232 requestApplyInsets();
1233 }
1234 }
1235 if (insets != null) {
Adrian Roosf7b74262017-11-22 14:21:01 +01001236 insets = insets.inset(consumedLeft, consumedTop, consumedRight, consumedBottom);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001237 }
1238 }
1239
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001240 if (forceConsumingNavBar) {
1241 mBackgroundInsets = Insets.of(mLastLeftInset, 0, mLastRightInset, mLastBottomInset);
1242 } else {
1243 mBackgroundInsets = Insets.NONE;
1244 }
1245 updateBackgroundDrawable();
1246
Wale Ogunwale8804af22015-11-17 09:18:15 -08001247 if (insets != null) {
1248 insets = insets.consumeStableInsets();
1249 }
1250 return insets;
1251 }
1252
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001253 /**
1254 * Updates the background drawable, applying padding to it in case we {@link #mBackgroundInsets}
1255 * are set.
1256 */
1257 private void updateBackgroundDrawable() {
Jorim Jaggid798fd32019-05-08 23:08:02 +02001258 // Background insets can be null if super constructor calls setBackgroundDrawable.
1259 if (mBackgroundInsets == null) {
1260 mBackgroundInsets = Insets.NONE;
1261 }
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001262 if (mBackgroundInsets.equals(mLastBackgroundInsets)
1263 && mLastOriginalBackgroundDrawable == mOriginalBackgroundDrawable) {
1264 return;
1265 }
Jorim Jaggi1ed68892019-04-08 14:51:42 +02001266 if (mOriginalBackgroundDrawable == null || mBackgroundInsets.equals(Insets.NONE)) {
Jorim Jaggi24cf50f2019-04-09 15:16:23 +02001267
1268 // Call super since we are intercepting setBackground on this class.
1269 super.setBackgroundDrawable(mOriginalBackgroundDrawable);
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001270 } else {
Jorim Jaggi24cf50f2019-04-09 15:16:23 +02001271
1272 // Call super since we are intercepting setBackground on this class.
1273 super.setBackgroundDrawable(new InsetDrawable(mOriginalBackgroundDrawable,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001274 mBackgroundInsets.left, mBackgroundInsets.top,
1275 mBackgroundInsets.right, mBackgroundInsets.bottom) {
1276
1277 /**
1278 * Return inner padding so we don't apply the padding again in
1279 * {@link DecorView#drawableChanged()}
1280 */
1281 @Override
1282 public boolean getPadding(Rect padding) {
1283 return getDrawable().getPadding(padding);
1284 }
1285 });
1286 }
1287 mLastBackgroundInsets = mBackgroundInsets;
1288 mLastOriginalBackgroundDrawable = mOriginalBackgroundDrawable;
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001289 }
1290
Jorim Jaggi24cf50f2019-04-09 15:16:23 +02001291 @Override
1292 public Drawable getBackground() {
1293 return mOriginalBackgroundDrawable;
1294 }
1295
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001296 private int calculateStatusBarColor() {
1297 return calculateBarColor(mWindow.getAttributes().flags, FLAG_TRANSLUCENT_STATUS,
Adrian Roos4c864592019-04-10 14:47:57 +02001298 mSemiTransparentBarColor, mWindow.mStatusBarColor,
1299 getWindowSystemUiVisibility(), SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
1300 mWindow.mEnsureStatusBarContrastWhenTransparent);
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001301 }
1302
1303 private int calculateNavigationBarColor() {
1304 return calculateBarColor(mWindow.getAttributes().flags, FLAG_TRANSLUCENT_NAVIGATION,
Adrian Roos4c864592019-04-10 14:47:57 +02001305 mSemiTransparentBarColor, mWindow.mNavigationBarColor,
1306 getWindowSystemUiVisibility(), SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
1307 mWindow.mEnsureNavigationBarContrastWhenTransparent
1308 && getContext().getResources().getBoolean(R.bool.config_navBarNeedsScrim));
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001309 }
1310
1311 public static int calculateBarColor(int flags, int translucentFlag, int semiTransparentBarColor,
Adrian Roos4c864592019-04-10 14:47:57 +02001312 int barColor, int sysuiVis, int lightSysuiFlag, boolean scrimTransparent) {
1313 if ((flags & translucentFlag) != 0) {
1314 return semiTransparentBarColor;
1315 } else if ((flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
1316 return Color.BLACK;
Winson Chungffc70a62019-07-01 15:32:43 -07001317 } else if (scrimTransparent && Color.alpha(barColor) == 0) {
Adrian Roos4c864592019-04-10 14:47:57 +02001318 boolean light = (sysuiVis & lightSysuiFlag) != 0;
1319 return light ? SCRIM_LIGHT : semiTransparentBarColor;
1320 } else {
1321 return barColor;
1322 }
Jorim Jaggi4fa78922015-11-30 17:13:56 -08001323 }
1324
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001325 private int getCurrentColor(ColorViewState state) {
1326 if (state.visible) {
1327 return state.color;
1328 } else {
1329 return 0;
1330 }
1331 }
1332
Wale Ogunwale8804af22015-11-17 09:18:15 -08001333 /**
1334 * Update a color view
1335 *
1336 * @param state the color view to update.
1337 * @param sysUiVis the current systemUiVisibility to apply.
1338 * @param color the current color to apply.
Jason Monkea506c62017-09-01 12:40:06 -04001339 * @param dividerColor the current divider color to apply.
Wale Ogunwale8804af22015-11-17 09:18:15 -08001340 * @param size the current size in the non-parent-matching dimension.
1341 * @param verticalBar if true the view is attached to a vertical edge, otherwise to a
1342 * horizontal edge,
Adrian Roos85d202b2016-06-02 16:27:47 -07001343 * @param sideMargin sideMargin for the color view.
Wale Ogunwale8804af22015-11-17 09:18:15 -08001344 * @param animate if true, the change will be animated.
1345 */
1346 private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
Jason Monkea506c62017-09-01 12:40:06 -04001347 int dividerColor, int size, boolean verticalBar, boolean seascape, int sideMargin,
Adrian Roos85d202b2016-06-02 16:27:47 -07001348 boolean animate, boolean force) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001349 state.present = state.attributes.isPresent(sysUiVis, mWindow.getAttributes().flags, force);
1350 boolean show = state.attributes.isVisible(state.present, color,
1351 mWindow.getAttributes().flags, force);
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001352 boolean showView = show && !isResizing() && size > 0;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001353
1354 boolean visibilityChanged = false;
1355 View view = state.view;
1356
1357 int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size;
1358 int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT;
Adrian Roos85d202b2016-06-02 16:27:47 -07001359 int resolvedGravity = verticalBar
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001360 ? (seascape ? state.attributes.seascapeGravity : state.attributes.horizontalGravity)
1361 : state.attributes.verticalGravity;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001362
1363 if (view == null) {
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001364 if (showView) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001365 state.view = view = new View(mContext);
Jason Monkea506c62017-09-01 12:40:06 -04001366 setColor(view, color, dividerColor, verticalBar, seascape);
Jorim Jaggi30d64f32017-04-07 16:33:17 +02001367 view.setTransitionName(state.attributes.transitionName);
1368 view.setId(state.attributes.id);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001369 visibilityChanged = true;
1370 view.setVisibility(INVISIBLE);
1371 state.targetVisibility = VISIBLE;
1372
1373 LayoutParams lp = new LayoutParams(resolvedWidth, resolvedHeight,
1374 resolvedGravity);
Adrian Roos85d202b2016-06-02 16:27:47 -07001375 if (seascape) {
1376 lp.leftMargin = sideMargin;
1377 } else {
1378 lp.rightMargin = sideMargin;
1379 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001380 addView(view, lp);
1381 updateColorViewTranslations();
1382 }
1383 } else {
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001384 int vis = showView ? VISIBLE : INVISIBLE;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001385 visibilityChanged = state.targetVisibility != vis;
1386 state.targetVisibility = vis;
1387 LayoutParams lp = (LayoutParams) view.getLayoutParams();
Adrian Roos85d202b2016-06-02 16:27:47 -07001388 int rightMargin = seascape ? 0 : sideMargin;
1389 int leftMargin = seascape ? sideMargin : 0;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001390 if (lp.height != resolvedHeight || lp.width != resolvedWidth
Adrian Roos85d202b2016-06-02 16:27:47 -07001391 || lp.gravity != resolvedGravity || lp.rightMargin != rightMargin
1392 || lp.leftMargin != leftMargin) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001393 lp.height = resolvedHeight;
1394 lp.width = resolvedWidth;
1395 lp.gravity = resolvedGravity;
1396 lp.rightMargin = rightMargin;
Adrian Roos85d202b2016-06-02 16:27:47 -07001397 lp.leftMargin = leftMargin;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001398 view.setLayoutParams(lp);
1399 }
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001400 if (showView) {
Jason Monkea506c62017-09-01 12:40:06 -04001401 setColor(view, color, dividerColor, verticalBar, seascape);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001402 }
1403 }
1404 if (visibilityChanged) {
1405 view.animate().cancel();
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001406 if (animate && !isResizing()) {
1407 if (showView) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001408 if (view.getVisibility() != VISIBLE) {
1409 view.setVisibility(VISIBLE);
1410 view.setAlpha(0.0f);
1411 }
1412 view.animate().alpha(1.0f).setInterpolator(mShowInterpolator).
1413 setDuration(mBarEnterExitDuration);
1414 } else {
1415 view.animate().alpha(0.0f).setInterpolator(mHideInterpolator)
1416 .setDuration(mBarEnterExitDuration)
1417 .withEndAction(new Runnable() {
1418 @Override
1419 public void run() {
1420 state.view.setAlpha(1.0f);
1421 state.view.setVisibility(INVISIBLE);
1422 }
1423 });
1424 }
1425 } else {
1426 view.setAlpha(1.0f);
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001427 view.setVisibility(showView ? VISIBLE : INVISIBLE);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001428 }
1429 }
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08001430 state.visible = show;
1431 state.color = color;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001432 }
1433
Jason Monkea506c62017-09-01 12:40:06 -04001434 private static void setColor(View v, int color, int dividerColor, boolean verticalBar,
1435 boolean seascape) {
1436 if (dividerColor != 0) {
1437 final Pair<Boolean, Boolean> dir = (Pair<Boolean, Boolean>) v.getTag();
1438 if (dir == null || dir.first != verticalBar || dir.second != seascape) {
1439 final int size = Math.round(
1440 TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
1441 v.getContext().getResources().getDisplayMetrics()));
1442 // Use an inset to make the divider line on the side that faces the app.
1443 final InsetDrawable d = new InsetDrawable(new ColorDrawable(color),
1444 verticalBar && !seascape ? size : 0,
1445 !verticalBar ? size : 0,
1446 verticalBar && seascape ? size : 0, 0);
1447 v.setBackground(new LayerDrawable(new Drawable[] {
1448 new ColorDrawable(dividerColor), d }));
1449 v.setTag(new Pair<>(verticalBar, seascape));
1450 } else {
1451 final LayerDrawable d = (LayerDrawable) v.getBackground();
1452 final InsetDrawable inset = ((InsetDrawable) d.getDrawable(1));
1453 ((ColorDrawable) inset.getDrawable()).setColor(color);
1454 ((ColorDrawable) d.getDrawable(0)).setColor(dividerColor);
1455 }
1456 } else {
1457 v.setTag(null);
1458 v.setBackgroundColor(color);
1459 }
1460 }
1461
Wale Ogunwale8804af22015-11-17 09:18:15 -08001462 private void updateColorViewTranslations() {
1463 // Put the color views back in place when they get moved off the screen
1464 // due to the the ViewRootImpl panning.
1465 int rootScrollY = mRootScrollY;
1466 if (mStatusColorViewState.view != null) {
1467 mStatusColorViewState.view.setTranslationY(rootScrollY > 0 ? rootScrollY : 0);
1468 }
1469 if (mNavigationColorViewState.view != null) {
1470 mNavigationColorViewState.view.setTranslationY(rootScrollY < 0 ? rootScrollY : 0);
1471 }
1472 }
1473
1474 private WindowInsets updateStatusGuard(WindowInsets insets) {
1475 boolean showStatusGuard = false;
1476 // Show the status guard when the non-overlay contextual action bar is showing
1477 if (mPrimaryActionModeView != null) {
1478 if (mPrimaryActionModeView.getLayoutParams() instanceof MarginLayoutParams) {
1479 // Insets are magic!
1480 final MarginLayoutParams mlp = (MarginLayoutParams)
1481 mPrimaryActionModeView.getLayoutParams();
1482 boolean mlpChanged = false;
1483 if (mPrimaryActionModeView.isShown()) {
1484 if (mTempRect == null) {
1485 mTempRect = new Rect();
1486 }
1487 final Rect rect = mTempRect;
1488
Adrian Roos27db0ca2019-05-29 16:12:09 +02001489 // Apply the insets that have not been applied by the contentParent yet.
1490 WindowInsets innerInsets =
1491 mWindow.mContentParent.computeSystemWindowInsets(insets, rect);
1492 int newTopMargin = innerInsets.getSystemWindowInsetTop();
1493 int newLeftMargin = innerInsets.getSystemWindowInsetLeft();
1494 int newRightMargin = innerInsets.getSystemWindowInsetRight();
Wale Ogunwale8804af22015-11-17 09:18:15 -08001495
Adrian Roos27db0ca2019-05-29 16:12:09 +02001496 // Must use root window insets for the guard, because the color views consume
1497 // the navigation bar inset if the window does not request LAYOUT_HIDE_NAV - but
1498 // the status guard is attached at the root.
1499 WindowInsets rootInsets = getRootWindowInsets();
1500 int newGuardLeftMargin = rootInsets.getSystemWindowInsetLeft();
1501 int newGuardRightMargin = rootInsets.getSystemWindowInsetRight();
1502
1503 if (mlp.topMargin != newTopMargin || mlp.leftMargin != newLeftMargin
1504 || mlp.rightMargin != newRightMargin) {
1505 mlpChanged = true;
1506 mlp.topMargin = newTopMargin;
1507 mlp.leftMargin = newLeftMargin;
1508 mlp.rightMargin = newRightMargin;
1509 }
1510
1511 if (newTopMargin > 0 && mStatusGuard == null) {
1512 mStatusGuard = new View(mContext);
1513 mStatusGuard.setVisibility(GONE);
1514 final LayoutParams lp = new LayoutParams(MATCH_PARENT,
1515 mlp.topMargin, Gravity.LEFT | Gravity.TOP);
1516 lp.leftMargin = newGuardLeftMargin;
1517 lp.rightMargin = newGuardRightMargin;
1518 addView(mStatusGuard, indexOfChild(mStatusColorViewState.view), lp);
1519 } else if (mStatusGuard != null) {
1520 final LayoutParams lp = (LayoutParams)
1521 mStatusGuard.getLayoutParams();
1522 if (lp.height != mlp.topMargin || lp.leftMargin != newGuardLeftMargin
1523 || lp.rightMargin != newGuardRightMargin) {
1524 lp.height = mlp.topMargin;
1525 lp.leftMargin = newGuardLeftMargin;
1526 lp.rightMargin = newGuardRightMargin;
1527 mStatusGuard.setLayoutParams(lp);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001528 }
1529 }
1530
1531 // The action mode's theme may differ from the app, so
1532 // always show the status guard above it if we have one.
1533 showStatusGuard = mStatusGuard != null;
1534
Adrian Roos27db0ca2019-05-29 16:12:09 +02001535 if (showStatusGuard && mStatusGuard.getVisibility() != VISIBLE) {
1536 // If it wasn't previously shown, the color may be stale
1537 updateStatusGuardColor();
1538 }
1539
Wale Ogunwale8804af22015-11-17 09:18:15 -08001540 // We only need to consume the insets if the action
1541 // mode is overlaid on the app content (e.g. it's
1542 // sitting in a FrameLayout, see
1543 // screen_simple_overlay_action_mode.xml).
1544 final boolean nonOverlay = (mWindow.getLocalFeaturesPrivate()
1545 & (1 << Window.FEATURE_ACTION_MODE_OVERLAY)) == 0;
Adrian Roosf7b74262017-11-22 14:21:01 +01001546 if (nonOverlay && showStatusGuard) {
1547 insets = insets.inset(0, insets.getSystemWindowInsetTop(), 0, 0);
1548 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001549 } else {
1550 // reset top margin
Adrian Roos27db0ca2019-05-29 16:12:09 +02001551 if (mlp.topMargin != 0 || mlp.leftMargin != 0 || mlp.rightMargin != 0) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001552 mlpChanged = true;
1553 mlp.topMargin = 0;
1554 }
1555 }
1556 if (mlpChanged) {
1557 mPrimaryActionModeView.setLayoutParams(mlp);
1558 }
1559 }
1560 }
1561 if (mStatusGuard != null) {
Adrian Roos27db0ca2019-05-29 16:12:09 +02001562 mStatusGuard.setVisibility(showStatusGuard ? VISIBLE : GONE);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001563 }
1564 return insets;
1565 }
1566
Adrian Roos27db0ca2019-05-29 16:12:09 +02001567 private void updateStatusGuardColor() {
1568 boolean lightStatusBar =
1569 (getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
1570 mStatusGuard.setBackgroundColor(lightStatusBar
1571 ? mContext.getColor(R.color.decor_view_status_guard_light)
1572 : mContext.getColor(R.color.decor_view_status_guard));
1573 }
1574
Winson Chung4d8681f2017-05-23 16:22:08 -07001575 /**
1576 * Overrides the view outline when the activity enters picture-in-picture to ensure that it has
1577 * an opaque shadow even if the window background is completely transparent. This only applies
1578 * to activities that are currently the task root.
1579 */
1580 public void updatePictureInPictureOutlineProvider(boolean isInPictureInPictureMode) {
1581 if (mIsInPictureInPictureMode == isInPictureInPictureMode) {
1582 return;
1583 }
1584
1585 if (isInPictureInPictureMode) {
1586 final Window.WindowControllerCallback callback =
1587 mWindow.getWindowControllerCallback();
1588 if (callback != null && callback.isTaskRoot()) {
1589 // Call super implementation directly as we don't want to save the PIP outline
1590 // provider to be restored
1591 super.setOutlineProvider(PIP_OUTLINE_PROVIDER);
1592 }
1593 } else {
1594 // Restore the previous outline provider
1595 if (getOutlineProvider() != mLastOutlineProvider) {
1596 setOutlineProvider(mLastOutlineProvider);
1597 }
1598 }
1599 mIsInPictureInPictureMode = isInPictureInPictureMode;
1600 }
1601
1602 @Override
1603 public void setOutlineProvider(ViewOutlineProvider provider) {
1604 super.setOutlineProvider(provider);
1605
1606 // Save the outline provider set to ensure that we can restore when the activity leaves PiP
1607 mLastOutlineProvider = provider;
1608 }
1609
Wale Ogunwale8804af22015-11-17 09:18:15 -08001610 private void drawableChanged() {
1611 if (mChanging) {
1612 return;
1613 }
1614
Jorim Jaggid798fd32019-05-08 23:08:02 +02001615 // Fields can be null if super constructor calls setBackgroundDrawable.
1616 Rect framePadding = mFramePadding != null ? mFramePadding : new Rect();
1617 Rect backgroundPadding = mBackgroundPadding != null ? mBackgroundPadding : new Rect();
1618
1619 setPadding(framePadding.left + backgroundPadding.left,
1620 framePadding.top + backgroundPadding.top,
1621 framePadding.right + backgroundPadding.right,
1622 framePadding.bottom + backgroundPadding.bottom);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001623 requestLayout();
1624 invalidate();
1625
1626 int opacity = PixelFormat.OPAQUE;
Wale Ogunwale3382ab12017-07-27 08:55:03 -07001627 final WindowConfiguration winConfig = getResources().getConfiguration().windowConfiguration;
1628 if (winConfig.hasWindowShadow()) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001629 // If the window has a shadow, it must be translucent.
1630 opacity = PixelFormat.TRANSLUCENT;
1631 } else{
1632 // Note: If there is no background, we will assume opaque. The
1633 // common case seems to be that an application sets there to be
1634 // no background so it can draw everything itself. For that,
1635 // we would like to assume OPAQUE and let the app force it to
1636 // the slower TRANSLUCENT mode if that is really what it wants.
1637 Drawable bg = getBackground();
1638 Drawable fg = getForeground();
1639 if (bg != null) {
1640 if (fg == null) {
1641 opacity = bg.getOpacity();
Jorim Jaggid798fd32019-05-08 23:08:02 +02001642 } else if (framePadding.left <= 0 && framePadding.top <= 0
1643 && framePadding.right <= 0 && framePadding.bottom <= 0) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001644 // If the frame padding is zero, then we can be opaque
1645 // if either the frame -or- the background is opaque.
1646 int fop = fg.getOpacity();
1647 int bop = bg.getOpacity();
1648 if (false)
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001649 Log.v(mLogTag, "Background opacity: " + bop + ", Frame opacity: " + fop);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001650 if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
1651 opacity = PixelFormat.OPAQUE;
1652 } else if (fop == PixelFormat.UNKNOWN) {
1653 opacity = bop;
1654 } else if (bop == PixelFormat.UNKNOWN) {
1655 opacity = fop;
1656 } else {
1657 opacity = Drawable.resolveOpacity(fop, bop);
1658 }
1659 } else {
1660 // For now we have to assume translucent if there is a
1661 // frame with padding... there is no way to tell if the
1662 // frame and background together will draw all pixels.
1663 if (false)
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001664 Log.v(mLogTag, "Padding: " + mFramePadding);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001665 opacity = PixelFormat.TRANSLUCENT;
1666 }
1667 }
1668 if (false)
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001669 Log.v(mLogTag, "Background: " + bg + ", Frame: " + fg);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001670 }
1671
1672 if (false)
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001673 Log.v(mLogTag, "Selected default opacity: " + opacity);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001674
1675 mDefaultOpacity = opacity;
1676 if (mFeatureId < 0) {
1677 mWindow.setDefaultWindowFormat(opacity);
1678 }
1679 }
1680
1681 @Override
1682 public void onWindowFocusChanged(boolean hasWindowFocus) {
1683 super.onWindowFocusChanged(hasWindowFocus);
1684
1685 // If the user is chording a menu shortcut, release the chord since
1686 // this window lost focus
1687 if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL) && !hasWindowFocus
1688 && mWindow.mPanelChordingKey != 0) {
1689 mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);
1690 }
1691
1692 final Window.Callback cb = mWindow.getCallback();
1693 if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
1694 cb.onWindowFocusChanged(hasWindowFocus);
1695 }
1696
1697 if (mPrimaryActionMode != null) {
1698 mPrimaryActionMode.onWindowFocusChanged(hasWindowFocus);
1699 }
1700 if (mFloatingActionMode != null) {
1701 mFloatingActionMode.onWindowFocusChanged(hasWindowFocus);
1702 }
Wale Ogunwale2b547c32015-11-18 10:33:22 -08001703
1704 updateElevation();
Wale Ogunwale8804af22015-11-17 09:18:15 -08001705 }
1706
1707 @Override
1708 protected void onAttachedToWindow() {
1709 super.onAttachedToWindow();
1710
1711 final Window.Callback cb = mWindow.getCallback();
1712 if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
1713 cb.onAttachedToWindow();
1714 }
1715
1716 if (mFeatureId == -1) {
1717 /*
1718 * The main window has been attached, try to restore any panels
1719 * that may have been open before. This is called in cases where
1720 * an activity is being killed for configuration change and the
1721 * menu was open. When the activity is recreated, the menu
1722 * should be shown again.
1723 */
1724 mWindow.openPanelsAfterRestore();
1725 }
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08001726
1727 if (!mWindowResizeCallbacksAdded) {
1728 // If there is no window callback installed there was no window set before. Set it now.
1729 // Note that our ViewRootImpl object will not change.
1730 getViewRootImpl().addWindowCallbacks(this);
1731 mWindowResizeCallbacksAdded = true;
1732 } else if (mBackdropFrameRenderer != null) {
1733 // We are resizing and this call happened due to a configuration change. Tell the
1734 // renderer about it.
1735 mBackdropFrameRenderer.onConfigurationChange();
1736 }
Andrii Kulian51c1b672017-04-07 18:39:32 -07001737 mWindow.onViewRootImplSet(getViewRootImpl());
Wale Ogunwale8804af22015-11-17 09:18:15 -08001738 }
1739
1740 @Override
1741 protected void onDetachedFromWindow() {
1742 super.onDetachedFromWindow();
1743
1744 final Window.Callback cb = mWindow.getCallback();
1745 if (cb != null && mFeatureId < 0) {
1746 cb.onDetachedFromWindow();
1747 }
1748
1749 if (mWindow.mDecorContentParent != null) {
1750 mWindow.mDecorContentParent.dismissPopups();
1751 }
1752
1753 if (mPrimaryActionModePopup != null) {
1754 removeCallbacks(mShowPrimaryActionModePopup);
1755 if (mPrimaryActionModePopup.isShowing()) {
1756 mPrimaryActionModePopup.dismiss();
1757 }
1758 mPrimaryActionModePopup = null;
1759 }
1760 if (mFloatingToolbar != null) {
1761 mFloatingToolbar.dismiss();
1762 mFloatingToolbar = null;
1763 }
1764
1765 PhoneWindow.PanelFeatureState st = mWindow.getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
1766 if (st != null && st.menu != null && mFeatureId < 0) {
1767 st.menu.close();
1768 }
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08001769
Jorim Jaggib2005a02016-04-08 14:13:30 -07001770 releaseThreadedRenderer();
1771
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08001772 if (mWindowResizeCallbacksAdded) {
1773 getViewRootImpl().removeWindowCallbacks(this);
1774 mWindowResizeCallbacksAdded = false;
1775 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001776 }
1777
1778 @Override
1779 public void onCloseSystemDialogs(String reason) {
1780 if (mFeatureId >= 0) {
1781 mWindow.closeAllPanels();
1782 }
1783 }
1784
1785 public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface() {
1786 return mFeatureId < 0 ? mWindow.mTakeSurfaceCallback : null;
1787 }
1788
1789 public InputQueue.Callback willYouTakeTheInputQueue() {
1790 return mFeatureId < 0 ? mWindow.mTakeInputQueueCallback : null;
1791 }
1792
1793 public void setSurfaceType(int type) {
1794 mWindow.setType(type);
1795 }
1796
1797 public void setSurfaceFormat(int format) {
1798 mWindow.setFormat(format);
1799 }
1800
1801 public void setSurfaceKeepScreenOn(boolean keepOn) {
1802 if (keepOn) mWindow.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1803 else mWindow.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1804 }
1805
1806 @Override
1807 public void onRootViewScrollYChanged(int rootScrollY) {
1808 mRootScrollY = rootScrollY;
Evan Rosky0d654cb2019-02-26 10:59:10 -08001809 if (mDecorCaptionView != null) {
1810 mDecorCaptionView.onRootViewScrollYChanged(rootScrollY);
1811 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001812 updateColorViewTranslations();
1813 }
1814
1815 private ActionMode createActionMode(
1816 int type, ActionMode.Callback2 callback, View originatingView) {
1817 switch (type) {
1818 case ActionMode.TYPE_PRIMARY:
1819 default:
1820 return createStandaloneActionMode(callback);
1821 case ActionMode.TYPE_FLOATING:
1822 return createFloatingActionMode(originatingView, callback);
1823 }
1824 }
1825
1826 private void setHandledActionMode(ActionMode mode) {
1827 if (mode.getType() == ActionMode.TYPE_PRIMARY) {
1828 setHandledPrimaryActionMode(mode);
1829 } else if (mode.getType() == ActionMode.TYPE_FLOATING) {
1830 setHandledFloatingActionMode(mode);
1831 }
1832 }
1833
1834 private ActionMode createStandaloneActionMode(ActionMode.Callback callback) {
1835 endOnGoingFadeAnimation();
1836 cleanupPrimaryActionMode();
Andrii Kulian8d6ac262016-06-08 13:14:19 -07001837 // We want to create new mPrimaryActionModeView in two cases: if there is no existing
1838 // instance at all, or if there is one, but it is detached from window. The latter case
1839 // might happen when app is resized in multi-window mode and decor view is preserved
1840 // along with the main app window. Keeping mPrimaryActionModeView reference doesn't cause
1841 // app memory leaks because killMode() is called when the dismiss animation ends and from
1842 // cleanupPrimaryActionMode() invocation above.
1843 if (mPrimaryActionModeView == null || !mPrimaryActionModeView.isAttachedToWindow()) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08001844 if (mWindow.isFloating()) {
1845 // Use the action bar theme.
1846 final TypedValue outValue = new TypedValue();
1847 final Resources.Theme baseTheme = mContext.getTheme();
1848 baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
1849
1850 final Context actionBarContext;
1851 if (outValue.resourceId != 0) {
1852 final Resources.Theme actionBarTheme = mContext.getResources().newTheme();
1853 actionBarTheme.setTo(baseTheme);
1854 actionBarTheme.applyStyle(outValue.resourceId, true);
1855
1856 actionBarContext = new ContextThemeWrapper(mContext, 0);
1857 actionBarContext.getTheme().setTo(actionBarTheme);
1858 } else {
1859 actionBarContext = mContext;
1860 }
1861
1862 mPrimaryActionModeView = new ActionBarContextView(actionBarContext);
1863 mPrimaryActionModePopup = new PopupWindow(actionBarContext, null,
1864 R.attr.actionModePopupWindowStyle);
1865 mPrimaryActionModePopup.setWindowLayoutType(
1866 WindowManager.LayoutParams.TYPE_APPLICATION);
1867 mPrimaryActionModePopup.setContentView(mPrimaryActionModeView);
1868 mPrimaryActionModePopup.setWidth(MATCH_PARENT);
1869
1870 actionBarContext.getTheme().resolveAttribute(
1871 R.attr.actionBarSize, outValue, true);
1872 final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
1873 actionBarContext.getResources().getDisplayMetrics());
1874 mPrimaryActionModeView.setContentHeight(height);
1875 mPrimaryActionModePopup.setHeight(WRAP_CONTENT);
1876 mShowPrimaryActionModePopup = new Runnable() {
1877 public void run() {
1878 mPrimaryActionModePopup.showAtLocation(
1879 mPrimaryActionModeView.getApplicationWindowToken(),
1880 Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
1881 endOnGoingFadeAnimation();
Wale Ogunwale8804af22015-11-17 09:18:15 -08001882
Chris Banese65b3fb2016-06-01 11:39:54 +01001883 if (shouldAnimatePrimaryActionModeView()) {
1884 mFadeAnim = ObjectAnimator.ofFloat(mPrimaryActionModeView, View.ALPHA,
1885 0f, 1f);
1886 mFadeAnim.addListener(new AnimatorListenerAdapter() {
1887 @Override
1888 public void onAnimationStart(Animator animation) {
1889 mPrimaryActionModeView.setVisibility(VISIBLE);
1890 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001891
Chris Banese65b3fb2016-06-01 11:39:54 +01001892 @Override
1893 public void onAnimationEnd(Animator animation) {
1894 mPrimaryActionModeView.setAlpha(1f);
1895 mFadeAnim = null;
1896 }
1897 });
1898 mFadeAnim.start();
1899 } else {
1900 mPrimaryActionModeView.setAlpha(1f);
1901 mPrimaryActionModeView.setVisibility(VISIBLE);
1902 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001903 }
1904 };
1905 } else {
Alan Viverette51efddb2017-04-05 10:00:01 -04001906 ViewStub stub = findViewById(R.id.action_mode_bar_stub);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001907 if (stub != null) {
1908 mPrimaryActionModeView = (ActionBarContextView) stub.inflate();
Andrii Kulian8d6ac262016-06-08 13:14:19 -07001909 mPrimaryActionModePopup = null;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001910 }
1911 }
1912 }
1913 if (mPrimaryActionModeView != null) {
1914 mPrimaryActionModeView.killMode();
1915 ActionMode mode = new StandaloneActionMode(
1916 mPrimaryActionModeView.getContext(), mPrimaryActionModeView,
1917 callback, mPrimaryActionModePopup == null);
1918 return mode;
1919 }
1920 return null;
1921 }
1922
1923 private void endOnGoingFadeAnimation() {
1924 if (mFadeAnim != null) {
1925 mFadeAnim.end();
1926 }
1927 }
1928
1929 private void setHandledPrimaryActionMode(ActionMode mode) {
1930 endOnGoingFadeAnimation();
1931 mPrimaryActionMode = mode;
1932 mPrimaryActionMode.invalidate();
1933 mPrimaryActionModeView.initForMode(mPrimaryActionMode);
1934 if (mPrimaryActionModePopup != null) {
1935 post(mShowPrimaryActionModePopup);
1936 } else {
Chris Banese65b3fb2016-06-01 11:39:54 +01001937 if (shouldAnimatePrimaryActionModeView()) {
1938 mFadeAnim = ObjectAnimator.ofFloat(mPrimaryActionModeView, View.ALPHA, 0f, 1f);
1939 mFadeAnim.addListener(new AnimatorListenerAdapter() {
1940 @Override
1941 public void onAnimationStart(Animator animation) {
1942 mPrimaryActionModeView.setVisibility(View.VISIBLE);
1943 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001944
Chris Banese65b3fb2016-06-01 11:39:54 +01001945 @Override
1946 public void onAnimationEnd(Animator animation) {
1947 mPrimaryActionModeView.setAlpha(1f);
1948 mFadeAnim = null;
1949 }
1950 });
1951 mFadeAnim.start();
1952 } else {
1953 mPrimaryActionModeView.setAlpha(1f);
1954 mPrimaryActionModeView.setVisibility(View.VISIBLE);
1955 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08001956 }
1957 mPrimaryActionModeView.sendAccessibilityEvent(
1958 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
1959 }
1960
Chris Banese65b3fb2016-06-01 11:39:54 +01001961 boolean shouldAnimatePrimaryActionModeView() {
1962 // We only to animate the action mode in if the decor has already been laid out.
1963 // If it hasn't been laid out, it hasn't been drawn to screen yet.
1964 return isLaidOut();
1965 }
1966
Wale Ogunwale8804af22015-11-17 09:18:15 -08001967 private ActionMode createFloatingActionMode(
1968 View originatingView, ActionMode.Callback2 callback) {
1969 if (mFloatingActionMode != null) {
1970 mFloatingActionMode.finish();
1971 }
1972 cleanupFloatingActionModeViews();
Tarandeep Singhc9c83a92017-08-29 14:39:22 -07001973 mFloatingToolbar = new FloatingToolbar(mWindow);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001974 final FloatingActionMode mode =
Abodunrinwa Toki17293cc2017-05-22 14:16:04 +01001975 new FloatingActionMode(mContext, callback, originatingView, mFloatingToolbar);
Wale Ogunwale8804af22015-11-17 09:18:15 -08001976 mFloatingActionModeOriginatingView = originatingView;
1977 mFloatingToolbarPreDrawListener =
1978 new ViewTreeObserver.OnPreDrawListener() {
1979 @Override
1980 public boolean onPreDraw() {
1981 mode.updateViewLocationInWindow();
1982 return true;
1983 }
1984 };
1985 return mode;
1986 }
1987
1988 private void setHandledFloatingActionMode(ActionMode mode) {
1989 mFloatingActionMode = mode;
Wale Ogunwale8804af22015-11-17 09:18:15 -08001990 mFloatingActionMode.invalidate(); // Will show the floating toolbar if necessary.
1991 mFloatingActionModeOriginatingView.getViewTreeObserver()
1992 .addOnPreDrawListener(mFloatingToolbarPreDrawListener);
1993 }
1994
1995 /**
Wale Ogunwale62a91d62015-11-18 11:44:10 -08001996 * Informs the decor if the caption is attached and visible.
Wale Ogunwale8804af22015-11-17 09:18:15 -08001997 * @param attachedAndVisible true when the decor is visible.
Wale Ogunwale62a91d62015-11-18 11:44:10 -08001998 * Note that this will even be called if there is no caption.
Wale Ogunwale8804af22015-11-17 09:18:15 -08001999 **/
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002000 void enableCaption(boolean attachedAndVisible) {
2001 if (mHasCaption != attachedAndVisible) {
2002 mHasCaption = attachedAndVisible;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002003 if (getForeground() != null) {
2004 drawableChanged();
2005 }
2006 }
2007 }
2008
Wale Ogunwale8804af22015-11-17 09:18:15 -08002009 void setWindow(PhoneWindow phoneWindow) {
2010 mWindow = phoneWindow;
2011 Context context = getContext();
2012 if (context instanceof DecorContext) {
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002013 DecorContext decorContext = (DecorContext) context;
2014 decorContext.setPhoneWindow(mWindow);
2015 }
2016 }
2017
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002018 @Override
chaviwa213d302018-04-23 13:34:36 -07002019 public Resources getResources() {
2020 // Make sure the Resources object is propogated from the Context since it can be updated in
2021 // the Context object.
2022 return getContext().getResources();
2023 }
2024
2025 @Override
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002026 protected void onConfigurationChanged(Configuration newConfig) {
2027 super.onConfigurationChanged(newConfig);
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002028
Garfield Tan3b9613c2018-12-26 17:08:51 -08002029 updateDecorCaptionStatus(newConfig);
2030
2031 updateAvailableWidth();
2032 initializeElevation();
2033 }
2034
sanryhuang2ed879f2018-10-08 23:10:22 +08002035 @Override
2036 public void onMovedToDisplay(int displayId, Configuration config) {
2037 super.onMovedToDisplay(displayId, config);
2038 // Have to explicitly update displayId because it may use DecorContext
2039 getContext().updateDisplay(displayId);
2040 }
2041
Garfield Tan3b9613c2018-12-26 17:08:51 -08002042 /**
2043 * Determines if the workspace is entirely covered by the window.
2044 * @return {@code true} when the window is filling the entire screen/workspace.
2045 **/
2046 private boolean isFillingScreen(Configuration config) {
2047 final boolean isFullscreen = config.windowConfiguration.getWindowingMode()
2048 == WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
2049 return isFullscreen && (0 != ((getWindowSystemUiVisibility() | getSystemUiVisibility())
Yunfan Chen1831e8e2019-04-24 15:54:49 +09002050 & View.SYSTEM_UI_FLAG_FULLSCREEN));
Garfield Tan3b9613c2018-12-26 17:08:51 -08002051 }
2052
2053 private void updateDecorCaptionStatus(Configuration config) {
2054 final boolean displayWindowDecor = config.windowConfiguration.hasWindowDecorCaption()
2055 && !isFillingScreen(config);
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002056 if (mDecorCaptionView == null && displayWindowDecor) {
2057 // Configuration now requires a caption.
2058 final LayoutInflater inflater = mWindow.getLayoutInflater();
2059 mDecorCaptionView = createDecorCaptionView(inflater);
2060 if (mDecorCaptionView != null) {
2061 if (mDecorCaptionView.getParent() == null) {
2062 addView(mDecorCaptionView, 0,
2063 new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
Wale Ogunwaleeb6722c2015-12-08 11:43:43 -08002064 }
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002065 removeView(mContentRoot);
2066 mDecorCaptionView.addView(mContentRoot,
2067 new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002068 }
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002069 } else if (mDecorCaptionView != null) {
2070 // We might have to change the kind of surface before we do anything else.
2071 mDecorCaptionView.onConfigurationChanged(displayWindowDecor);
2072 enableCaption(displayWindowDecor);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002073 }
2074 }
2075
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002076 void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002077 if (mBackdropFrameRenderer != null) {
Filip Gruszczynskia40fd092016-01-07 16:38:11 -08002078 loadBackgroundDrawablesIfNeeded();
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002079 mBackdropFrameRenderer.onResourcesLoaded(
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002080 this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08002081 mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
2082 getCurrentColor(mNavigationColorViewState));
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002083 }
2084
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002085 mDecorCaptionView = createDecorCaptionView(inflater);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002086 final View root = inflater.inflate(layoutResource, null);
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002087 if (mDecorCaptionView != null) {
2088 if (mDecorCaptionView.getParent() == null) {
2089 addView(mDecorCaptionView,
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002090 new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
2091 }
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002092 mDecorCaptionView.addView(root,
Filip Gruszczynski63250652015-11-18 14:43:01 -08002093 new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002094 } else {
Jorim Jaggi0a13bfd2016-02-04 18:34:50 -08002095
2096 // Put it below the color views.
2097 addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002098 }
2099 mContentRoot = (ViewGroup) root;
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002100 initializeElevation();
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002101 }
2102
Filip Gruszczynskia40fd092016-01-07 16:38:11 -08002103 private void loadBackgroundDrawablesIfNeeded() {
2104 if (mResizingBackgroundDrawable == null) {
Nader Jawad56c68bc2018-04-24 17:08:51 -07002105 mResizingBackgroundDrawable = getResizingBackgroundDrawable(mWindow.mBackgroundDrawable,
2106 mWindow.mBackgroundFallbackDrawable, mWindow.isTranslucent()
2107 || mWindow.isShowingWallpaper());
Winson Chung1af8eda2016-02-05 17:55:56 +00002108 if (mResizingBackgroundDrawable == null) {
2109 // We shouldn't really get here as the background fallback should be always
2110 // available since it is defaulted by the system.
2111 Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow);
2112 }
Filip Gruszczynskia40fd092016-01-07 16:38:11 -08002113 }
2114 if (mCaptionBackgroundDrawable == null) {
2115 mCaptionBackgroundDrawable = getContext().getDrawable(
2116 R.drawable.decor_caption_title_focused);
2117 }
Chong Zhang0df63d52016-02-24 15:39:53 -08002118 if (mResizingBackgroundDrawable != null) {
2119 mLastBackgroundDrawableCb = mResizingBackgroundDrawable.getCallback();
2120 mResizingBackgroundDrawable.setCallback(null);
2121 }
Filip Gruszczynskia40fd092016-01-07 16:38:11 -08002122 }
2123
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002124 // Free floating overlapping windows require a caption.
2125 private DecorCaptionView createDecorCaptionView(LayoutInflater inflater) {
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002126 DecorCaptionView decorCaptionView = null;
2127 for (int i = getChildCount() - 1; i >= 0 && decorCaptionView == null; i--) {
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002128 View view = getChildAt(i);
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002129 if (view instanceof DecorCaptionView) {
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002130 // The decor was most likely saved from a relaunch - so reuse it.
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002131 decorCaptionView = (DecorCaptionView) view;
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002132 removeViewAt(i);
2133 }
2134 }
2135 final WindowManager.LayoutParams attrs = mWindow.getAttributes();
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002136 final boolean isApplication = attrs.type == TYPE_BASE_APPLICATION ||
Chong Zhangfea963e2016-08-15 17:14:16 -07002137 attrs.type == TYPE_APPLICATION || attrs.type == TYPE_DRAWN_APPLICATION;
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002138 final WindowConfiguration winConfig = getResources().getConfiguration().windowConfiguration;
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002139 // Only a non floating application window on one of the allowed workspaces can get a caption
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002140 if (!mWindow.isFloating() && isApplication && winConfig.hasWindowDecorCaption()) {
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002141 // Dependent on the brightness of the used title we either use the
2142 // dark or the light button frame.
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002143 if (decorCaptionView == null) {
2144 decorCaptionView = inflateDecorCaptionView(inflater);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002145 }
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002146 decorCaptionView.setPhoneWindow(mWindow, true /*showDecor*/);
Wale Ogunwale8cc5a742015-11-17 15:41:05 -08002147 } else {
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002148 decorCaptionView = null;
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002149 }
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002150
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002151 // Tell the decor if it has a visible caption.
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002152 enableCaption(decorCaptionView != null);
2153 return decorCaptionView;
2154 }
2155
2156 private DecorCaptionView inflateDecorCaptionView(LayoutInflater inflater) {
2157 final Context context = getContext();
2158 // We make a copy of the inflater, so it has the right context associated with it.
2159 inflater = inflater.from(context);
2160 final DecorCaptionView view = (DecorCaptionView) inflater.inflate(R.layout.decor_caption,
2161 null);
2162 setDecorCaptionShade(context, view);
2163 return view;
2164 }
2165
2166 private void setDecorCaptionShade(Context context, DecorCaptionView view) {
2167 final int shade = mWindow.getDecorCaptionShade();
2168 switch (shade) {
2169 case DECOR_CAPTION_SHADE_LIGHT:
2170 setLightDecorCaptionShade(view);
2171 break;
2172 case DECOR_CAPTION_SHADE_DARK:
2173 setDarkDecorCaptionShade(view);
2174 break;
2175 default: {
2176 TypedValue value = new TypedValue();
2177 context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
2178 // We invert the shade depending on brightness of the theme. Dark shade for light
2179 // theme and vice versa. Thanks to this the buttons should be visible on the
2180 // background.
2181 if (Color.luminance(value.data) < 0.5) {
2182 setLightDecorCaptionShade(view);
2183 } else {
2184 setDarkDecorCaptionShade(view);
2185 }
2186 break;
2187 }
2188 }
2189 }
2190
2191 void updateDecorCaptionShade() {
2192 if (mDecorCaptionView != null) {
2193 setDecorCaptionShade(getContext(), mDecorCaptionView);
2194 }
2195 }
2196
2197 private void setLightDecorCaptionShade(DecorCaptionView view) {
2198 view.findViewById(R.id.maximize_window).setBackgroundResource(
2199 R.drawable.decor_maximize_button_light);
2200 view.findViewById(R.id.close_window).setBackgroundResource(
2201 R.drawable.decor_close_button_light);
2202 }
2203
2204 private void setDarkDecorCaptionShade(DecorCaptionView view) {
2205 view.findViewById(R.id.maximize_window).setBackgroundResource(
2206 R.drawable.decor_maximize_button_dark);
2207 view.findViewById(R.id.close_window).setBackgroundResource(
2208 R.drawable.decor_close_button_dark);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002209 }
2210
2211 /**
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002212 * Returns the color used to fill areas the app has not rendered content to yet when the
2213 * user is resizing the window of an activity in multi-window mode.
2214 */
Nader Jawad56c68bc2018-04-24 17:08:51 -07002215 public static Drawable getResizingBackgroundDrawable(@Nullable Drawable backgroundDrawable,
2216 @Nullable Drawable fallbackDrawable, boolean windowTranslucent) {
2217 if (backgroundDrawable != null) {
2218 return enforceNonTranslucentBackground(backgroundDrawable, windowTranslucent);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002219 }
2220
Nader Jawad56c68bc2018-04-24 17:08:51 -07002221 if (fallbackDrawable != null) {
2222 return enforceNonTranslucentBackground(fallbackDrawable, windowTranslucent);
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002223 }
Jorim Jaggi8e879f12016-05-25 16:41:49 -07002224 return new ColorDrawable(Color.BLACK);
2225 }
2226
2227 /**
2228 * Enforces a drawable to be non-translucent to act as a background if needed, i.e. if the
2229 * window is not translucent.
2230 */
2231 private static Drawable enforceNonTranslucentBackground(Drawable drawable,
2232 boolean windowTranslucent) {
2233 if (!windowTranslucent && drawable instanceof ColorDrawable) {
2234 ColorDrawable colorDrawable = (ColorDrawable) drawable;
2235 int color = colorDrawable.getColor();
2236 if (Color.alpha(color) != 255) {
2237 ColorDrawable copy = (ColorDrawable) colorDrawable.getConstantState().newDrawable()
2238 .mutate();
2239 copy.setColor(
2240 Color.argb(255, Color.red(color), Color.green(color), Color.blue(color)));
2241 return copy;
2242 }
2243 }
2244 return drawable;
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002245 }
2246
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002247 void clearContentView() {
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002248 if (mDecorCaptionView != null) {
Filip Gruszczynski63250652015-11-18 14:43:01 -08002249 mDecorCaptionView.removeContentView();
Wale Ogunwale0d7e9122015-11-17 10:45:06 -08002250 } else {
Jorim Jaggi6e0ce282015-12-01 15:19:49 -08002251 // This window doesn't have caption, so we need to remove everything except our views
2252 // we might have added.
2253 for (int i = getChildCount() - 1; i >= 0; i--) {
2254 View v = getChildAt(i);
2255 if (v != mStatusColorViewState.view && v != mNavigationColorViewState.view
Yohei Yukawa8f162c62018-01-10 13:18:09 -08002256 && v != mStatusGuard) {
Jorim Jaggi6e0ce282015-12-01 15:19:49 -08002257 removeViewAt(i);
2258 }
2259 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08002260 }
2261 }
2262
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002263 @Override
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08002264 public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
2265 Rect stableInsets) {
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002266 if (mBackdropFrameRenderer != null) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08002267 mBackdropFrameRenderer.setTargetRect(newBounds, fullscreen, systemInsets, stableInsets);
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002268 }
2269 }
2270
2271 @Override
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08002272 public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002273 Rect stableInsets, int resizeMode) {
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002274 if (mWindow.isDestroyed()) {
2275 // If the owner's window is gone, we should not be able to come here anymore.
2276 releaseThreadedRenderer();
2277 return;
2278 }
2279 if (mBackdropFrameRenderer != null) {
2280 return;
2281 }
Stan Iliev45faba52016-06-28 13:33:15 -04002282 final ThreadedRenderer renderer = getThreadedRenderer();
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002283 if (renderer != null) {
Filip Gruszczynskia40fd092016-01-07 16:38:11 -08002284 loadBackgroundDrawablesIfNeeded();
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002285 mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer,
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002286 initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08002287 mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
2288 getCurrentColor(mNavigationColorViewState), fullscreen, systemInsets,
Garfield Tanfbd8ea62018-10-16 17:09:49 -07002289 stableInsets);
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002290
2291 // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
2292 // If we want to get the shadow shown while resizing, we would need to elevate a new
2293 // element which owns the caption and has the elevation.
2294 updateElevation();
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002295
2296 updateColorViews(null /* insets */, false);
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002297 }
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002298 mResizeMode = resizeMode;
2299 getViewRootImpl().requestInvalidateRootRenderNode();
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002300 }
2301
2302 @Override
2303 public void onWindowDragResizeEnd() {
2304 releaseThreadedRenderer();
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002305 updateColorViews(null /* insets */, false);
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002306 mResizeMode = RESIZE_MODE_INVALID;
2307 getViewRootImpl().requestInvalidateRootRenderNode();
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002308 }
2309
2310 @Override
2311 public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
2312 if (mBackdropFrameRenderer == null) {
2313 return false;
2314 }
2315 return mBackdropFrameRenderer.onContentDrawn(offsetX, offsetY, sizeX, sizeY);
2316 }
2317
2318 @Override
2319 public void onRequestDraw(boolean reportNextDraw) {
2320 if (mBackdropFrameRenderer != null) {
2321 mBackdropFrameRenderer.onRequestDraw(reportNextDraw);
2322 } else if (reportNextDraw) {
2323 // If render thread is gone, just report immediately.
2324 if (isAttachedToWindow()) {
2325 getViewRootImpl().reportDrawFinish();
2326 }
2327 }
2328 }
2329
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002330 @Override
John Reck32f140aa62018-10-04 15:08:24 -07002331 public void onPostDraw(RecordingCanvas canvas) {
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002332 drawResizingShadowIfNeeded(canvas);
Jorim Jaggi86d30ff2019-06-11 17:54:07 +02002333 drawLegacyNavigationBarBackground(canvas);
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002334 }
2335
2336 private void initResizingPaints() {
2337 final int startColor = mContext.getResources().getColor(
2338 R.color.resize_shadow_start_color, null);
2339 final int endColor = mContext.getResources().getColor(
2340 R.color.resize_shadow_end_color, null);
2341 final int middleColor = (startColor + endColor) / 2;
2342 mHorizontalResizeShadowPaint.setShader(new LinearGradient(
2343 0, 0, 0, mResizeShadowSize, new int[] { startColor, middleColor, endColor },
2344 new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
2345 mVerticalResizeShadowPaint.setShader(new LinearGradient(
2346 0, 0, mResizeShadowSize, 0, new int[] { startColor, middleColor, endColor },
2347 new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
2348 }
2349
John Reck32f140aa62018-10-04 15:08:24 -07002350 private void drawResizingShadowIfNeeded(RecordingCanvas canvas) {
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002351 if (mResizeMode != RESIZE_MODE_DOCKED_DIVIDER || mWindow.mIsFloating
2352 || mWindow.isTranslucent()
Jorim Jaggi8e879f12016-05-25 16:41:49 -07002353 || mWindow.isShowingWallpaper()) {
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002354 return;
2355 }
2356 canvas.save();
2357 canvas.translate(0, getHeight() - mFrameOffsets.bottom);
2358 canvas.drawRect(0, 0, getWidth(), mResizeShadowSize, mHorizontalResizeShadowPaint);
2359 canvas.restore();
2360 canvas.save();
2361 canvas.translate(getWidth() - mFrameOffsets.right, 0);
2362 canvas.drawRect(0, 0, mResizeShadowSize, getHeight(), mVerticalResizeShadowPaint);
2363 canvas.restore();
2364 }
2365
Jorim Jaggi86d30ff2019-06-11 17:54:07 +02002366 private void drawLegacyNavigationBarBackground(RecordingCanvas canvas) {
2367 if (!mDrawLegacyNavigationBarBackground) {
2368 return;
2369 }
2370 View v = mNavigationColorViewState.view;
2371 if (v == null) {
2372 return;
2373 }
2374 canvas.drawRect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom(),
2375 mLegacyNavigationBarBackgroundPaint);
2376 }
2377
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002378 /** Release the renderer thread which is usually done when the user stops resizing. */
2379 private void releaseThreadedRenderer() {
Chong Zhangd3fd96c2016-02-08 18:25:24 -08002380 if (mResizingBackgroundDrawable != null && mLastBackgroundDrawableCb != null) {
2381 mResizingBackgroundDrawable.setCallback(mLastBackgroundDrawableCb);
2382 mLastBackgroundDrawableCb = null;
2383 }
2384
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002385 if (mBackdropFrameRenderer != null) {
2386 mBackdropFrameRenderer.releaseRenderer();
2387 mBackdropFrameRenderer = null;
2388 // Bring the shadow back.
2389 updateElevation();
2390 }
2391 }
2392
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002393 private boolean isResizing() {
2394 return mBackdropFrameRenderer != null;
2395 }
2396
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002397 /**
2398 * The elevation gets set for the first time and the framework needs to be informed that
2399 * the surface layer gets created with the shadow size in mind.
2400 */
2401 private void initializeElevation() {
2402 // TODO(skuhne): Call setMaxElevation here accordingly after b/22668382 got fixed.
2403 mAllowUpdateElevation = false;
2404 updateElevation();
2405 }
2406
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002407 private void updateElevation() {
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002408 float elevation = 0;
2409 final boolean wasAdjustedForStack = mElevationAdjustedForStack;
2410 // Do not use a shadow when we are in resizing mode (mBackdropFrameRenderer not null)
2411 // since the shadow is bound to the content size and not the target size.
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002412 final int windowingMode =
2413 getResources().getConfiguration().windowConfiguration.getWindowingMode();
2414 if ((windowingMode == WINDOWING_MODE_FREEFORM) && !isResizing()) {
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002415 elevation = hasWindowFocus() ?
2416 DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
Jaewan Kim880eff62016-04-27 10:36:35 +09002417 // Add a maximum shadow height value to the top level view.
2418 // Note that pinned stack doesn't have focus
2419 // so maximum shadow height adjustment isn't needed.
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002420 // TODO(skuhne): Remove this if clause once b/22668382 got fixed.
Robert Carr232b5f82017-04-17 15:11:35 -07002421 if (!mAllowUpdateElevation) {
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002422 elevation = DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
2423 }
2424 // Convert the DP elevation into physical pixels.
2425 elevation = dipToPx(elevation);
2426 mElevationAdjustedForStack = true;
Wale Ogunwale3382ab12017-07-27 08:55:03 -07002427 } else if (windowingMode == WINDOWING_MODE_PINNED) {
Robert Carr32bcb102018-01-29 15:03:23 -08002428 elevation = dipToPx(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP);
Robert Carr232b5f82017-04-17 15:11:35 -07002429 mElevationAdjustedForStack = true;
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002430 } else {
2431 mElevationAdjustedForStack = false;
2432 }
2433
2434 // Don't change the elevation if we didn't previously adjust it for the stack it was in
2435 // or it didn't change.
2436 if ((wasAdjustedForStack || mElevationAdjustedForStack)
2437 && getElevation() != elevation) {
Garfield Tanfbd8ea62018-10-16 17:09:49 -07002438 if (!isResizing()) {
2439 mWindow.setElevation(elevation);
2440 } else {
2441 // Just suppress the shadow when resizing, don't adjust surface insets because it'll
2442 // cause a flicker when drag resize for freeform window starts. #onContentDrawn()
2443 // will compensate the offset when passing to BackdropFrameRenderer.
2444 setElevation(elevation);
2445 }
Wale Ogunwalebf9eefc2015-11-17 14:47:52 -08002446 }
2447 }
2448
Wale Ogunwale8cc5a742015-11-17 15:41:05 -08002449 boolean isShowingCaption() {
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002450 return mDecorCaptionView != null && mDecorCaptionView.isCaptionShowing();
Wale Ogunwale8cc5a742015-11-17 15:41:05 -08002451 }
2452
2453 int getCaptionHeight() {
Wale Ogunwale62a91d62015-11-18 11:44:10 -08002454 return isShowingCaption() ? mDecorCaptionView.getCaptionHeight() : 0;
Wale Ogunwale8cc5a742015-11-17 15:41:05 -08002455 }
2456
Wale Ogunwale2b547c32015-11-18 10:33:22 -08002457 /**
2458 * Converts a DIP measure into physical pixels.
2459 * @param dip The dip value.
2460 * @return Returns the number of pixels.
2461 */
2462 private float dipToPx(float dip) {
2463 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
2464 getResources().getDisplayMetrics());
2465 }
2466
Filip Gruszczynski3dec0812015-12-09 08:42:41 -08002467 /**
2468 * Provide an override of the caption background drawable.
2469 */
2470 void setUserCaptionBackgroundDrawable(Drawable drawable) {
2471 mUserCaptionBackgroundDrawable = drawable;
2472 if (mBackdropFrameRenderer != null) {
2473 mBackdropFrameRenderer.setUserCaptionBackgroundDrawable(drawable);
2474 }
2475 }
2476
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002477 private static String getTitleSuffix(WindowManager.LayoutParams params) {
2478 if (params == null) {
2479 return "";
2480 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002481 final String[] split = params.getTitle().toString().split("\\.");
2482 if (split.length > 0) {
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002483 return split[split.length - 1];
2484 } else {
2485 return "";
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002486 }
2487 }
2488
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002489 void updateLogTag(WindowManager.LayoutParams params) {
2490 mLogTag = TAG + "[" + getTitleSuffix(params) + "]";
2491 }
2492
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002493 private void updateAvailableWidth() {
2494 Resources res = getResources();
2495 mAvailableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
2496 res.getConfiguration().screenWidthDp, res.getDisplayMetrics());
2497 }
2498
Clara Bayarri75e09792015-07-29 16:20:40 +01002499 /**
2500 * @hide
2501 */
2502 @Override
Clara Bayarrifcd7e802016-03-10 12:58:18 +00002503 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list, int deviceId) {
Clara Bayarri75e09792015-07-29 16:20:40 +01002504 final PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false);
Michael Wright936f27c2017-04-11 23:23:42 +01002505 final Menu menu = st != null ? st.menu : null;
2506 if (!mWindow.isDestroyed() && mWindow.getCallback() != null) {
2507 mWindow.getCallback().onProvideKeyboardShortcuts(list, menu, deviceId);
Clara Bayarri75e09792015-07-29 16:20:40 +01002508 }
2509 }
2510
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002511 @Override
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08002512 public void dispatchPointerCaptureChanged(boolean hasCapture) {
2513 super.dispatchPointerCaptureChanged(hasCapture);
2514 if (!mWindow.isDestroyed() && mWindow.getCallback() != null) {
2515 mWindow.getCallback().onPointerCaptureChanged(hasCapture);
2516 }
2517 }
2518
2519 @Override
Phil Weaverf00cd142017-03-03 13:44:00 -08002520 public int getAccessibilityViewId() {
2521 return AccessibilityNodeInfo.ROOT_ITEM_ID;
2522 }
2523
2524 @Override
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08002525 public String toString() {
2526 return "DecorView@" + Integer.toHexString(this.hashCode()) + "["
2527 + getTitleSuffix(mWindow.getAttributes()) + "]";
2528 }
2529
Wale Ogunwale8804af22015-11-17 09:18:15 -08002530 private static class ColorViewState {
2531 View view = null;
2532 int targetVisibility = View.INVISIBLE;
2533 boolean present = false;
Jorim Jaggi04c2fbd2015-12-02 15:11:45 -08002534 boolean visible;
2535 int color;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002536
Jorim Jaggi30d64f32017-04-07 16:33:17 +02002537 final ColorViewAttributes attributes;
2538
2539 ColorViewState(ColorViewAttributes attributes) {
2540 this.attributes = attributes;
2541 }
2542 }
2543
2544 public static class ColorViewAttributes {
2545
Wale Ogunwale8804af22015-11-17 09:18:15 -08002546 final int id;
2547 final int systemUiHideFlag;
2548 final int translucentFlag;
2549 final int verticalGravity;
2550 final int horizontalGravity;
Adrian Roos85d202b2016-06-02 16:27:47 -07002551 final int seascapeGravity;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002552 final String transitionName;
2553 final int hideWindowFlag;
2554
Jorim Jaggi30d64f32017-04-07 16:33:17 +02002555 private ColorViewAttributes(int systemUiHideFlag, int translucentFlag, int verticalGravity,
2556 int horizontalGravity, int seascapeGravity, String transitionName, int id,
2557 int hideWindowFlag) {
Wale Ogunwale8804af22015-11-17 09:18:15 -08002558 this.id = id;
2559 this.systemUiHideFlag = systemUiHideFlag;
2560 this.translucentFlag = translucentFlag;
2561 this.verticalGravity = verticalGravity;
2562 this.horizontalGravity = horizontalGravity;
Adrian Roos85d202b2016-06-02 16:27:47 -07002563 this.seascapeGravity = seascapeGravity;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002564 this.transitionName = transitionName;
2565 this.hideWindowFlag = hideWindowFlag;
2566 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +02002567
2568 public boolean isPresent(int sysUiVis, int windowFlags, boolean force) {
2569 return (sysUiVis & systemUiHideFlag) == 0
2570 && (windowFlags & hideWindowFlag) == 0
2571 && ((windowFlags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
2572 || force);
2573 }
2574
2575 public boolean isVisible(boolean present, int color, int windowFlags, boolean force) {
2576 return present
2577 && (color & Color.BLACK) != 0
2578 && ((windowFlags & translucentFlag) == 0 || force);
2579 }
2580
2581 public boolean isVisible(int sysUiVis, int color, int windowFlags, boolean force) {
2582 final boolean present = isPresent(sysUiVis, windowFlags, force);
2583 return isVisible(present, color, windowFlags, force);
2584 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08002585 }
2586
2587 /**
2588 * Clears out internal references when the action mode is destroyed.
2589 */
2590 private class ActionModeCallback2Wrapper extends ActionMode.Callback2 {
2591 private final ActionMode.Callback mWrapped;
2592
2593 public ActionModeCallback2Wrapper(ActionMode.Callback wrapped) {
2594 mWrapped = wrapped;
2595 }
2596
2597 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
2598 return mWrapped.onCreateActionMode(mode, menu);
2599 }
2600
2601 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
2602 requestFitSystemWindows();
2603 return mWrapped.onPrepareActionMode(mode, menu);
2604 }
2605
2606 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
2607 return mWrapped.onActionItemClicked(mode, item);
2608 }
2609
2610 public void onDestroyActionMode(ActionMode mode) {
2611 mWrapped.onDestroyActionMode(mode);
2612 final boolean isMncApp = mContext.getApplicationInfo().targetSdkVersion
Jorim Jaggi8f5701b2016-04-04 18:36:02 -07002613 >= M;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002614 final boolean isPrimary;
2615 final boolean isFloating;
2616 if (isMncApp) {
2617 isPrimary = mode == mPrimaryActionMode;
2618 isFloating = mode == mFloatingActionMode;
2619 if (!isPrimary && mode.getType() == ActionMode.TYPE_PRIMARY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002620 Log.e(mLogTag, "Destroying unexpected ActionMode instance of TYPE_PRIMARY; "
Wale Ogunwale8804af22015-11-17 09:18:15 -08002621 + mode + " was not the current primary action mode! Expected "
2622 + mPrimaryActionMode);
2623 }
2624 if (!isFloating && mode.getType() == ActionMode.TYPE_FLOATING) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002625 Log.e(mLogTag, "Destroying unexpected ActionMode instance of TYPE_FLOATING; "
Wale Ogunwale8804af22015-11-17 09:18:15 -08002626 + mode + " was not the current floating action mode! Expected "
2627 + mFloatingActionMode);
2628 }
2629 } else {
2630 isPrimary = mode.getType() == ActionMode.TYPE_PRIMARY;
2631 isFloating = mode.getType() == ActionMode.TYPE_FLOATING;
2632 }
2633 if (isPrimary) {
2634 if (mPrimaryActionModePopup != null) {
2635 removeCallbacks(mShowPrimaryActionModePopup);
2636 }
2637 if (mPrimaryActionModeView != null) {
2638 endOnGoingFadeAnimation();
Andrii Kulian8d6ac262016-06-08 13:14:19 -07002639 // Store action mode view reference, so we can access it safely when animation
2640 // ends. mPrimaryActionModePopup is set together with mPrimaryActionModeView,
2641 // so no need to store reference to it in separate variable.
2642 final ActionBarContextView lastActionModeView = mPrimaryActionModeView;
Wale Ogunwale8804af22015-11-17 09:18:15 -08002643 mFadeAnim = ObjectAnimator.ofFloat(mPrimaryActionModeView, View.ALPHA,
2644 1f, 0f);
2645 mFadeAnim.addListener(new Animator.AnimatorListener() {
Andrii Kulian8d6ac262016-06-08 13:14:19 -07002646
Wale Ogunwale8804af22015-11-17 09:18:15 -08002647 @Override
2648 public void onAnimationStart(Animator animation) {
2649
2650 }
2651
2652 @Override
2653 public void onAnimationEnd(Animator animation) {
Andrii Kulian8d6ac262016-06-08 13:14:19 -07002654 // If mPrimaryActionModeView has changed - it means that we've
2655 // cleared the content while preserving decor view. We don't
2656 // want to change the state of new instances accidentally here.
2657 if (lastActionModeView == mPrimaryActionModeView) {
2658 lastActionModeView.setVisibility(GONE);
2659 if (mPrimaryActionModePopup != null) {
2660 mPrimaryActionModePopup.dismiss();
2661 }
2662 lastActionModeView.killMode();
2663 mFadeAnim = null;
Adrian Roos27db0ca2019-05-29 16:12:09 +02002664 requestApplyInsets();
Wale Ogunwale8804af22015-11-17 09:18:15 -08002665 }
Wale Ogunwale8804af22015-11-17 09:18:15 -08002666 }
2667
2668 @Override
2669 public void onAnimationCancel(Animator animation) {
2670
2671 }
2672
2673 @Override
2674 public void onAnimationRepeat(Animator animation) {
2675
2676 }
2677 });
2678 mFadeAnim.start();
2679 }
2680
2681 mPrimaryActionMode = null;
2682 } else if (isFloating) {
2683 cleanupFloatingActionModeViews();
2684 mFloatingActionMode = null;
2685 }
2686 if (mWindow.getCallback() != null && !mWindow.isDestroyed()) {
2687 try {
2688 mWindow.getCallback().onActionModeFinished(mode);
2689 } catch (AbstractMethodError ame) {
2690 // Older apps might not implement this callback method.
2691 }
2692 }
2693 requestFitSystemWindows();
2694 }
2695
2696 @Override
2697 public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
2698 if (mWrapped instanceof ActionMode.Callback2) {
2699 ((ActionMode.Callback2) mWrapped).onGetContentRect(mode, view, outRect);
2700 } else {
2701 super.onGetContentRect(mode, view, outRect);
2702 }
2703 }
2704 }
2705}