Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 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 | |
| 17 | package com.android.server.wm; |
| 18 | |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 19 | import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; |
| 20 | import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 21 | import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; |
| 22 | import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; |
Tarandeep Singh | b9538cd | 2020-02-20 17:51:18 -0800 | [diff] [blame] | 23 | import static android.view.InsetsController.ANIMATION_TYPE_HIDE; |
| 24 | import static android.view.InsetsController.ANIMATION_TYPE_SHOW; |
Tiger Huang | 332793b | 2019-10-29 23:21:27 +0800 | [diff] [blame] | 25 | import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; |
| 26 | import static android.view.InsetsState.ITYPE_STATUS_BAR; |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 27 | import static android.view.SyncRtSurfaceTransactionApplier.applyParams; |
wilsonshih | e832194 | 2019-10-18 18:39:46 +0800 | [diff] [blame] | 28 | import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 29 | import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION; |
| 30 | |
| 31 | import android.annotation.Nullable; |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 32 | import android.app.StatusBarManager; |
| 33 | import android.util.IntArray; |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 34 | import android.util.SparseArray; |
| 35 | import android.view.InsetsAnimationControlCallbacks; |
| 36 | import android.view.InsetsAnimationControlImpl; |
Jorim Jaggi | 6d5c801 | 2020-02-28 01:40:27 +0100 | [diff] [blame] | 37 | import android.view.InsetsAnimationControlRunner; |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 38 | import android.view.InsetsController; |
| 39 | import android.view.InsetsSourceControl; |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 40 | import android.view.InsetsState; |
Tiger Huang | 332793b | 2019-10-29 23:21:27 +0800 | [diff] [blame] | 41 | import android.view.InsetsState.InternalInsetsType; |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 42 | import android.view.SurfaceControl; |
| 43 | import android.view.SyncRtSurfaceTransactionApplier; |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 44 | import android.view.ViewRootImpl; |
Adrian Roos | db5b0c2 | 2020-02-12 15:05:27 -0800 | [diff] [blame] | 45 | import android.view.WindowInsetsAnimation; |
Jorim Jaggi | 6d5c801 | 2020-02-28 01:40:27 +0100 | [diff] [blame] | 46 | import android.view.WindowInsetsAnimation.Bounds; |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 47 | import android.view.WindowInsetsAnimationControlListener; |
| 48 | |
Tiger Huang | a1663403 | 2020-02-05 17:10:03 +0800 | [diff] [blame] | 49 | import com.android.internal.annotations.VisibleForTesting; |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 50 | import com.android.server.DisplayThread; |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 51 | |
| 52 | /** |
| 53 | * Policy that implements who gets control over the windows generating insets. |
| 54 | */ |
| 55 | class InsetsPolicy { |
| 56 | |
| 57 | private final InsetsStateController mStateController; |
| 58 | private final DisplayContent mDisplayContent; |
| 59 | private final DisplayPolicy mPolicy; |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 60 | private final IntArray mShowingTransientTypes = new IntArray(); |
| 61 | |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 62 | /** For resetting visibilities of insets sources. */ |
Tiger Huang | af2c7c4 | 2020-05-12 19:53:18 +0800 | [diff] [blame] | 63 | private final InsetsControlTarget mDummyControlTarget = new InsetsControlTarget() { |
| 64 | |
| 65 | @Override |
| 66 | public void notifyInsetsControlChanged() { |
| 67 | boolean hasLeash = false; |
| 68 | final InsetsSourceControl[] controls = |
| 69 | mStateController.getControlsForDispatch(this); |
| 70 | if (controls == null) { |
| 71 | return; |
| 72 | } |
| 73 | for (InsetsSourceControl control : controls) { |
| 74 | final @InternalInsetsType int type = control.getType(); |
| 75 | if (mShowingTransientTypes.indexOf(type) != -1) { |
| 76 | // The visibilities of transient bars will be handled with animations. |
| 77 | continue; |
| 78 | } |
| 79 | final SurfaceControl leash = control.getLeash(); |
| 80 | if (leash != null) { |
| 81 | hasLeash = true; |
| 82 | |
| 83 | // We use alpha to control the visibility here which aligns the logic at |
| 84 | // SurfaceAnimator.createAnimationLeash |
| 85 | mDisplayContent.getPendingTransaction().setAlpha( |
| 86 | leash, InsetsState.getDefaultVisibility(type) ? 1f : 0f); |
| 87 | } |
| 88 | } |
| 89 | if (hasLeash) { |
| 90 | mDisplayContent.scheduleAnimation(); |
| 91 | } |
| 92 | } |
| 93 | }; |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 94 | |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 95 | private WindowState mFocusedWin; |
Tiger Huang | 4a7835f | 2019-11-06 00:07:56 +0800 | [diff] [blame] | 96 | private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR); |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 97 | private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR); |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 98 | private boolean mAnimatingShown; |
| 99 | private final float[] mTmpFloat9 = new float[9]; |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 100 | |
| 101 | InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) { |
| 102 | mStateController = stateController; |
| 103 | mDisplayContent = displayContent; |
| 104 | mPolicy = displayContent.getDisplayPolicy(); |
| 105 | } |
| 106 | |
| 107 | /** Updates the target which can control system bars. */ |
| 108 | void updateBarControlTarget(@Nullable WindowState focusedWin) { |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 109 | if (mFocusedWin != focusedWin){ |
| 110 | abortTransient(); |
| 111 | } |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 112 | mFocusedWin = focusedWin; |
Tiger Huang | 4a7835f | 2019-11-06 00:07:56 +0800 | [diff] [blame] | 113 | mStateController.onBarControlTargetChanged(getStatusControlTarget(focusedWin), |
| 114 | getFakeStatusControlTarget(focusedWin), |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 115 | getNavControlTarget(focusedWin), |
| 116 | getFakeNavControlTarget(focusedWin)); |
| 117 | if (ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) { |
| 118 | return; |
| 119 | } |
Tiger Huang | 4a7835f | 2019-11-06 00:07:56 +0800 | [diff] [blame] | 120 | mStatusBar.setVisible(focusedWin == null |
| 121 | || focusedWin != getStatusControlTarget(focusedWin) |
Jorim Jaggi | 0dd0cf9 | 2019-12-27 15:17:44 +0100 | [diff] [blame] | 122 | || focusedWin.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).isVisible()); |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 123 | mNavBar.setVisible(focusedWin == null |
| 124 | || focusedWin != getNavControlTarget(focusedWin) |
Jorim Jaggi | 0dd0cf9 | 2019-12-27 15:17:44 +0100 | [diff] [blame] | 125 | || focusedWin.getRequestedInsetsState().getSource(ITYPE_NAVIGATION_BAR) |
| 126 | .isVisible()); |
Tiger Huang | 9ff42bd | 2020-05-01 03:27:33 +0800 | [diff] [blame] | 127 | mPolicy.updateHideNavInputEventReceiver(); |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 128 | } |
| 129 | |
Tiger Huang | 332793b | 2019-10-29 23:21:27 +0800 | [diff] [blame] | 130 | boolean isHidden(@InternalInsetsType int type) { |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 131 | final InsetsSourceProvider provider = mStateController.peekSourceProvider(type); |
| 132 | return provider != null && provider.hasWindow() && !provider.getSource().isVisible(); |
| 133 | } |
| 134 | |
| 135 | void showTransient(IntArray types) { |
| 136 | boolean changed = false; |
| 137 | for (int i = types.size() - 1; i >= 0; i--) { |
| 138 | final int type = types.get(i); |
| 139 | if (mShowingTransientTypes.indexOf(type) != -1) { |
| 140 | continue; |
| 141 | } |
| 142 | if (!isHidden(type)) { |
| 143 | continue; |
| 144 | } |
| 145 | mShowingTransientTypes.add(type); |
| 146 | changed = true; |
| 147 | } |
| 148 | if (changed) { |
Tiger Huang | a1663403 | 2020-02-05 17:10:03 +0800 | [diff] [blame] | 149 | mPolicy.getStatusBarManagerInternal().showTransient(mDisplayContent.getDisplayId(), |
| 150 | mShowingTransientTypes.toArray()); |
| 151 | updateBarControlTarget(mFocusedWin); |
Tiger Huang | e480e5f | 2020-04-16 23:26:49 +0800 | [diff] [blame] | 152 | |
| 153 | // The leashes can be created while updating bar control target. The surface transaction |
| 154 | // of the new leashes might not be applied yet. The callback posted here ensures we can |
| 155 | // get the valid leashes because the surface transaction will be applied in the next |
| 156 | // animation frame which will be triggered if a new leash is created. |
| 157 | mDisplayContent.mWmService.mAnimator.getChoreographer().postFrameCallback(time -> { |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 158 | synchronized (mDisplayContent.mWmService.mGlobalLock) { |
Tiger Huang | e480e5f | 2020-04-16 23:26:49 +0800 | [diff] [blame] | 159 | final InsetsState state = new InsetsState(mStateController.getRawInsetsState()); |
| 160 | startAnimation(true /* show */, () -> { |
| 161 | synchronized (mDisplayContent.mWmService.mGlobalLock) { |
| 162 | mStateController.notifyInsetsChanged(); |
| 163 | } |
| 164 | }, state); |
| 165 | mStateController.onInsetsModified(mDummyControlTarget, state); |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 166 | } |
Tiger Huang | e480e5f | 2020-04-16 23:26:49 +0800 | [diff] [blame] | 167 | }); |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 168 | } |
| 169 | } |
| 170 | |
| 171 | void hideTransient() { |
| 172 | if (mShowingTransientTypes.size() == 0) { |
| 173 | return; |
| 174 | } |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 175 | InsetsState state = new InsetsState(mStateController.getRawInsetsState()); |
Tiger Huang | a1663403 | 2020-02-05 17:10:03 +0800 | [diff] [blame] | 176 | startAnimation(false /* show */, () -> { |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 177 | synchronized (mDisplayContent.mWmService.mGlobalLock) { |
| 178 | mShowingTransientTypes.clear(); |
| 179 | mStateController.notifyInsetsChanged(); |
| 180 | updateBarControlTarget(mFocusedWin); |
| 181 | } |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 182 | }, state); |
| 183 | mStateController.onInsetsModified(mDummyControlTarget, state); |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 184 | } |
| 185 | |
Tiger Huang | 4a7835f | 2019-11-06 00:07:56 +0800 | [diff] [blame] | 186 | boolean isTransient(@InternalInsetsType int type) { |
| 187 | return mShowingTransientTypes.indexOf(type) != -1; |
| 188 | } |
| 189 | |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 190 | /** |
| 191 | * @see InsetsStateController#getInsetsForDispatch |
| 192 | */ |
| 193 | InsetsState getInsetsForDispatch(WindowState target) { |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 194 | InsetsState originalState = mStateController.getInsetsForDispatch(target); |
| 195 | InsetsState state = originalState; |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 196 | for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 197 | state = new InsetsState(state); |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 198 | state.setSourceVisible(mShowingTransientTypes.get(i), false); |
| 199 | } |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 200 | if (mFocusedWin != null && getStatusControlTarget(mFocusedWin) == mDummyControlTarget) { |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 201 | if (state == originalState) { |
| 202 | state = new InsetsState(state); |
| 203 | } |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 204 | state.setSourceVisible(ITYPE_STATUS_BAR, mFocusedWin.getRequestedInsetsState()); |
| 205 | } |
| 206 | if (mFocusedWin != null && getNavControlTarget(mFocusedWin) == mDummyControlTarget) { |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 207 | if (state == originalState) { |
| 208 | state = new InsetsState(state); |
| 209 | } |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 210 | state.setSourceVisible(ITYPE_NAVIGATION_BAR, mFocusedWin.getRequestedInsetsState()); |
| 211 | } |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 212 | return state; |
| 213 | } |
| 214 | |
| 215 | void onInsetsModified(WindowState windowState, InsetsState state) { |
| 216 | mStateController.onInsetsModified(windowState, state); |
| 217 | checkAbortTransient(windowState, state); |
| 218 | if (ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) { |
| 219 | return; |
| 220 | } |
Tiger Huang | 4a7835f | 2019-11-06 00:07:56 +0800 | [diff] [blame] | 221 | if (windowState == getStatusControlTarget(mFocusedWin)) { |
| 222 | mStatusBar.setVisible(state.getSource(ITYPE_STATUS_BAR).isVisible()); |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 223 | } |
| 224 | if (windowState == getNavControlTarget(mFocusedWin)) { |
Tiger Huang | 332793b | 2019-10-29 23:21:27 +0800 | [diff] [blame] | 225 | mNavBar.setVisible(state.getSource(ITYPE_NAVIGATION_BAR).isVisible()); |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 226 | } |
Tiger Huang | 9ff42bd | 2020-05-01 03:27:33 +0800 | [diff] [blame] | 227 | mPolicy.updateHideNavInputEventReceiver(); |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 228 | } |
| 229 | |
| 230 | /** |
| 231 | * Called when a window modified the insets state. If the window set a insets source to visible |
| 232 | * while it is shown transiently, we need to abort the transient state. |
| 233 | * |
| 234 | * @param windowState who changed the insets state. |
| 235 | * @param state the modified insets state. |
| 236 | */ |
| 237 | private void checkAbortTransient(WindowState windowState, InsetsState state) { |
| 238 | if (mShowingTransientTypes.size() != 0) { |
| 239 | IntArray abortTypes = new IntArray(); |
| 240 | for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { |
| 241 | final int type = mShowingTransientTypes.get(i); |
| 242 | if (mStateController.isFakeTarget(type, windowState) |
| 243 | && state.getSource(type).isVisible()) { |
| 244 | mShowingTransientTypes.remove(i); |
| 245 | abortTypes.add(type); |
| 246 | } |
| 247 | } |
| 248 | if (abortTypes.size() > 0) { |
| 249 | mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(), |
| 250 | abortTypes.toArray()); |
| 251 | updateBarControlTarget(mFocusedWin); |
| 252 | } |
| 253 | } |
| 254 | } |
| 255 | |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 256 | private void abortTransient() { |
| 257 | mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(), |
| 258 | mShowingTransientTypes.toArray()); |
| 259 | mShowingTransientTypes.clear(); |
| 260 | updateBarControlTarget(mFocusedWin); |
| 261 | } |
| 262 | |
Tiger Huang | 4a7835f | 2019-11-06 00:07:56 +0800 | [diff] [blame] | 263 | private @Nullable InsetsControlTarget getFakeStatusControlTarget( |
| 264 | @Nullable WindowState focused) { |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 265 | return getStatusControlTarget(focused) == mDummyControlTarget ? focused : null; |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 266 | } |
| 267 | |
| 268 | private @Nullable InsetsControlTarget getFakeNavControlTarget(@Nullable WindowState focused) { |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 269 | return getNavControlTarget(focused) == mDummyControlTarget ? focused : null; |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 270 | } |
| 271 | |
Tiger Huang | 4a7835f | 2019-11-06 00:07:56 +0800 | [diff] [blame] | 272 | private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin) { |
Tiger Huang | 332793b | 2019-10-29 23:21:27 +0800 | [diff] [blame] | 273 | if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) { |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 274 | return mDummyControlTarget; |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 275 | } |
Jorim Jaggi | 026ed75 | 2020-01-29 00:30:24 +0100 | [diff] [blame] | 276 | if (focusedWin == mPolicy.getNotificationShade()) { |
| 277 | // Notification shade has control anyways, no reason to force anything. |
| 278 | return focusedWin; |
| 279 | } |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 280 | if (forceShowsSystemBarsForWindowingMode()) { |
| 281 | // Status bar is forcibly shown for the windowing mode which is a steady state. |
| 282 | // We don't want the client to control the status bar, and we will dispatch the real |
| 283 | // visibility of status bar to the client. |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 284 | return null; |
| 285 | } |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 286 | if (forceShowsStatusBarTransiently()) { |
| 287 | // Status bar is forcibly shown transiently, and its new visibility won't be |
| 288 | // dispatched to the client so that we can keep the layout stable. We will dispatch the |
| 289 | // fake control to the client, so that it can re-show the bar during this scenario. |
| 290 | return mDummyControlTarget; |
| 291 | } |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 292 | return focusedWin; |
| 293 | } |
| 294 | |
| 295 | private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin) { |
Tiger Huang | 332793b | 2019-10-29 23:21:27 +0800 | [diff] [blame] | 296 | if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) { |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 297 | return mDummyControlTarget; |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 298 | } |
Jorim Jaggi | 026ed75 | 2020-01-29 00:30:24 +0100 | [diff] [blame] | 299 | if (focusedWin == mPolicy.getNotificationShade()) { |
| 300 | // Notification shade has control anyways, no reason to force anything. |
| 301 | return focusedWin; |
| 302 | } |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 303 | if (forceShowsSystemBarsForWindowingMode()) { |
| 304 | // Navigation bar is forcibly shown for the windowing mode which is a steady state. |
| 305 | // We don't want the client to control the navigation bar, and we will dispatch the real |
| 306 | // visibility of navigation bar to the client. |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 307 | return null; |
| 308 | } |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 309 | if (forceShowsNavigationBarTransiently()) { |
| 310 | // Navigation bar is forcibly shown transiently, and its new visibility won't be |
| 311 | // dispatched to the client so that we can keep the layout stable. We will dispatch the |
| 312 | // fake control to the client, so that it can re-show the bar during this scenario. |
| 313 | return mDummyControlTarget; |
| 314 | } |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 315 | return focusedWin; |
| 316 | } |
| 317 | |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 318 | private boolean forceShowsStatusBarTransiently() { |
| 319 | final WindowState win = mPolicy.getStatusBar(); |
| 320 | return win != null && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0; |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 321 | } |
| 322 | |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 323 | private boolean forceShowsNavigationBarTransiently() { |
| 324 | final WindowState win = mPolicy.getNotificationShade(); |
| 325 | return win != null |
| 326 | && (win.mAttrs.privateFlags & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0; |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 327 | } |
| 328 | |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 329 | private boolean forceShowsSystemBarsForWindowingMode() { |
Andrii Kulian | 4c0fd0d | 2020-03-29 13:32:14 -0700 | [diff] [blame] | 330 | final boolean isDockedStackVisible = mDisplayContent.getDefaultTaskDisplayArea() |
| 331 | .isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); |
| 332 | final boolean isFreeformStackVisible = mDisplayContent.getDefaultTaskDisplayArea() |
| 333 | .isStackVisible(WINDOWING_MODE_FREEFORM); |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 334 | final boolean isResizing = mDisplayContent.getDockedDividerController().isResizing(); |
| 335 | |
| 336 | // We need to force system bars when the docked stack is visible, when the freeform stack |
| 337 | // is visible but also when we are resizing for the transitions when docked stack |
| 338 | // visibility changes. |
JianYang Liu | ae86b3f | 2020-04-03 20:20:35 -0700 | [diff] [blame] | 339 | return isDockedStackVisible |
| 340 | || isFreeformStackVisible |
| 341 | || isResizing |
| 342 | || mPolicy.getForceShowSystemBars(); |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 343 | } |
| 344 | |
Tiger Huang | a1663403 | 2020-02-05 17:10:03 +0800 | [diff] [blame] | 345 | @VisibleForTesting |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 346 | void startAnimation(boolean show, Runnable callback, InsetsState state) { |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 347 | int typesReady = 0; |
| 348 | final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); |
Tiger Huang | a1663403 | 2020-02-05 17:10:03 +0800 | [diff] [blame] | 349 | final IntArray showingTransientTypes = mShowingTransientTypes; |
| 350 | for (int i = showingTransientTypes.size() - 1; i >= 0; i--) { |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 351 | int type = showingTransientTypes.get(i); |
| 352 | InsetsSourceProvider provider = mStateController.getSourceProvider(type); |
Tiger Huang | b9510ef | 2020-03-03 23:03:39 +0800 | [diff] [blame] | 353 | InsetsSourceControl control = provider.getControl(mDummyControlTarget); |
Tiger Huang | a1663403 | 2020-02-05 17:10:03 +0800 | [diff] [blame] | 354 | if (control == null || control.getLeash() == null) { |
| 355 | continue; |
| 356 | } |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 357 | typesReady |= InsetsState.toPublicType(type); |
Tiger Huang | a1663403 | 2020-02-05 17:10:03 +0800 | [diff] [blame] | 358 | controls.put(control.getType(), new InsetsSourceControl(control)); |
Jorim Jaggi | 49b9f6c | 2020-03-24 22:28:38 +0100 | [diff] [blame] | 359 | state.setSourceVisible(type, show); |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 360 | } |
| 361 | controlAnimationUnchecked(typesReady, controls, show, callback); |
| 362 | } |
| 363 | |
| 364 | private void controlAnimationUnchecked(int typesReady, |
| 365 | SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback) { |
| 366 | InsetsPolicyAnimationControlListener listener = |
Jorim Jaggi | 5875cca | 2020-03-17 13:44:57 +0100 | [diff] [blame] | 367 | new InsetsPolicyAnimationControlListener(show, callback, typesReady); |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 368 | listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show); |
| 369 | } |
| 370 | |
Jorim Jaggi | 956ca41 | 2019-01-07 14:49:14 +0100 | [diff] [blame] | 371 | private class BarWindow { |
| 372 | |
| 373 | private final int mId; |
| 374 | private @StatusBarManager.WindowVisibleState int mState = |
| 375 | StatusBarManager.WINDOW_STATE_SHOWING; |
| 376 | |
| 377 | BarWindow(int id) { |
| 378 | mId = id; |
| 379 | } |
| 380 | |
| 381 | private void setVisible(boolean visible) { |
| 382 | final int state = visible ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN; |
| 383 | if (mState != state) { |
| 384 | mState = state; |
| 385 | mPolicy.getStatusBarManagerInternal().setWindowState( |
| 386 | mDisplayContent.getDisplayId(), mId, state); |
| 387 | } |
| 388 | } |
| 389 | } |
| 390 | |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 391 | private class InsetsPolicyAnimationControlListener extends |
| 392 | InsetsController.InternalAnimationControlListener { |
| 393 | Runnable mFinishCallback; |
| 394 | InsetsPolicyAnimationControlCallbacks mControlCallbacks; |
| 395 | |
Jorim Jaggi | 5875cca | 2020-03-17 13:44:57 +0100 | [diff] [blame] | 396 | InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) { |
| 397 | super(show, false /* hasCallbacks */, types); |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 398 | mFinishCallback = finishCallback; |
| 399 | mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this); |
| 400 | } |
| 401 | |
| 402 | @Override |
| 403 | protected void onAnimationFinish() { |
| 404 | super.onAnimationFinish(); |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 405 | DisplayThread.getHandler().post(mFinishCallback); |
| 406 | } |
| 407 | |
| 408 | private class InsetsPolicyAnimationControlCallbacks implements |
| 409 | InsetsAnimationControlCallbacks { |
| 410 | private InsetsAnimationControlImpl mAnimationControl = null; |
| 411 | private InsetsPolicyAnimationControlListener mListener; |
| 412 | |
| 413 | InsetsPolicyAnimationControlCallbacks(InsetsPolicyAnimationControlListener listener) { |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 414 | mListener = listener; |
| 415 | } |
| 416 | |
| 417 | private void controlAnimationUnchecked(int typesReady, |
| 418 | SparseArray<InsetsSourceControl> controls, boolean show) { |
| 419 | if (typesReady == 0) { |
| 420 | // nothing to animate. |
| 421 | return; |
| 422 | } |
| 423 | mAnimatingShown = show; |
| 424 | |
| 425 | mAnimationControl = new InsetsAnimationControlImpl(controls, |
| 426 | mFocusedWin.getDisplayContent().getBounds(), getState(), |
| 427 | mListener, typesReady, this, mListener.getDurationMs(), |
Jorim Jaggi | 5875cca | 2020-03-17 13:44:57 +0100 | [diff] [blame] | 428 | InsetsController.SYSTEM_BARS_INTERPOLATOR, |
Tarandeep Singh | b9538cd | 2020-02-20 17:51:18 -0800 | [diff] [blame] | 429 | show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE); |
Tiger Huang | a1663403 | 2020-02-05 17:10:03 +0800 | [diff] [blame] | 430 | SurfaceAnimationThread.getHandler().post( |
| 431 | () -> mListener.onReady(mAnimationControl, typesReady)); |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 432 | } |
| 433 | |
Tiger Huang | a1663403 | 2020-02-05 17:10:03 +0800 | [diff] [blame] | 434 | /** Called on SurfaceAnimationThread without global WM lock held. */ |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 435 | @Override |
Adrian Roos | 6a4448f | 2020-04-01 15:01:08 +0200 | [diff] [blame] | 436 | public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) { |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 437 | InsetsState state = getState(); |
| 438 | if (mAnimationControl.applyChangeInsets(state)) { |
| 439 | mAnimationControl.finish(mAnimatingShown); |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | @Override |
Jorim Jaggi | 6d5c801 | 2020-02-28 01:40:27 +0100 | [diff] [blame] | 444 | public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) { |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 445 | // Nothing's needed here. Finish steps is handled in the listener |
| 446 | // onAnimationFinished callback. |
| 447 | } |
| 448 | |
| 449 | /** |
| 450 | * This method will return a state with fullscreen frame override. No need to make copy |
| 451 | * after getting state from this method. |
| 452 | * @return The client insets state with full display frame override. |
| 453 | */ |
| 454 | private InsetsState getState() { |
| 455 | // To animate the transient animation correctly, we need to let the state hold |
| 456 | // the full display frame. |
| 457 | InsetsState overrideState = new InsetsState(mFocusedWin.getRequestedInsetsState(), |
| 458 | true); |
| 459 | overrideState.setDisplayFrame(mFocusedWin.getDisplayContent().getBounds()); |
| 460 | return overrideState; |
| 461 | } |
| 462 | |
Tiger Huang | a1663403 | 2020-02-05 17:10:03 +0800 | [diff] [blame] | 463 | /** Called on SurfaceAnimationThread without global WM lock held. */ |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 464 | @Override |
| 465 | public void applySurfaceParams( |
| 466 | final SyncRtSurfaceTransactionApplier.SurfaceParams... params) { |
| 467 | SurfaceControl.Transaction t = new SurfaceControl.Transaction(); |
| 468 | for (int i = params.length - 1; i >= 0; i--) { |
| 469 | SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i]; |
| 470 | applyParams(t, surfaceParams, mTmpFloat9); |
| 471 | } |
| 472 | t.apply(); |
Jorim Jaggi | 6d5c801 | 2020-02-28 01:40:27 +0100 | [diff] [blame] | 473 | t.close(); |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 474 | } |
| 475 | |
Rob Carr | 3a367c4 | 2020-03-10 15:51:35 -0700 | [diff] [blame] | 476 | // Since we don't push applySurfaceParams to a Handler-queue we don't need |
| 477 | // to push release in this case. |
| 478 | @Override |
| 479 | public void releaseSurfaceControlFromRt(SurfaceControl sc) { |
| 480 | sc.release(); |
| 481 | } |
| 482 | |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 483 | @Override |
| 484 | public void startAnimation(InsetsAnimationControlImpl controller, |
| 485 | WindowInsetsAnimationControlListener listener, int types, |
Adrian Roos | db5b0c2 | 2020-02-12 15:05:27 -0800 | [diff] [blame] | 486 | WindowInsetsAnimation animation, |
Jorim Jaggi | 6d5c801 | 2020-02-28 01:40:27 +0100 | [diff] [blame] | 487 | Bounds bounds) { |
Yunfan Chen | b5d2db7 | 2019-12-06 15:43:43 +0900 | [diff] [blame] | 488 | } |
| 489 | } |
| 490 | } |
Jorim Jaggi | 2862047 | 2019-01-02 23:21:49 +0100 | [diff] [blame] | 491 | } |