TaskStack.java revision 1402c2efe815bbdfdbc2d3e8e25fff367d272dd4
137b74a387bb3993387029859c2d9d051c41c724eStephen Hines/* 2affc150dc44fab1911775a49636d0ce85333b634Zonr Chang * Copyright (C) 2013 The Android Open Source Project 3affc150dc44fab1911775a49636d0ce85333b634Zonr Chang * 4affc150dc44fab1911775a49636d0ce85333b634Zonr Chang * Licensed under the Apache License, Version 2.0 (the "License"); 5affc150dc44fab1911775a49636d0ce85333b634Zonr Chang * you may not use this file except in compliance with the License. 6affc150dc44fab1911775a49636d0ce85333b634Zonr Chang * You may obtain a copy of the License at 7affc150dc44fab1911775a49636d0ce85333b634Zonr Chang * 8affc150dc44fab1911775a49636d0ce85333b634Zonr Chang * http://www.apache.org/licenses/LICENSE-2.0 937b74a387bb3993387029859c2d9d051c41c724eStephen Hines * 1037b74a387bb3993387029859c2d9d051c41c724eStephen Hines * Unless required by applicable law or agreed to in writing, software 1137b74a387bb3993387029859c2d9d051c41c724eStephen Hines * distributed under the License is distributed on an "AS IS" BASIS, 12affc150dc44fab1911775a49636d0ce85333b634Zonr Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13affc150dc44fab1911775a49636d0ce85333b634Zonr Chang * See the License for the specific language governing permissions and 1437b74a387bb3993387029859c2d9d051c41c724eStephen Hines * limitations under the License. 1537b74a387bb3993387029859c2d9d051c41c724eStephen Hines */ 16affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 17affc150dc44fab1911775a49636d0ce85333b634Zonr Changpackage com.android.server.wm; 18affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 1937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; 2037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport static android.app.ActivityManager.StackId.DOCKED_STACK_ID; 21affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport static android.app.ActivityManager.StackId.PINNED_STACK_ID; 22affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport static android.content.res.Configuration.DENSITY_DPI_UNDEFINED; 23affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport static android.content.res.Configuration.ORIENTATION_PORTRAIT; 24affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport static android.view.WindowManager.DOCKED_BOTTOM; 25affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport static android.view.WindowManager.DOCKED_INVALID; 2637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport static android.view.WindowManager.DOCKED_LEFT; 2737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport static android.view.WindowManager.DOCKED_RIGHT; 2837b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport static android.view.WindowManager.DOCKED_TOP; 2937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; 30affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; 31affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 3237b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport static com.android.server.wm.WindowManagerService.H.RESIZE_STACK; 3337b74a387bb3993387029859c2d9d051c41c724eStephen Hines 34affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport android.app.ActivityManager.StackId; 3537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport android.content.res.Configuration; 36affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport android.graphics.Rect; 3737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport android.os.Debug; 38affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport android.os.RemoteException; 3937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport android.util.EventLog; 40affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport android.util.Slog; 4137b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport android.util.SparseArray; 42affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport android.view.DisplayInfo; 4337b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport android.view.Surface; 44affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport android.view.animation.PathInterpolator; 4537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport android.view.SurfaceControl; 46affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 4737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport com.android.internal.policy.DividerSnapAlgorithm; 48affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; 4937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport com.android.internal.policy.DockedDividerUtils; 50affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport com.android.server.EventLogTags; 5137b74a387bb3993387029859c2d9d051c41c724eStephen Hines 52affc150dc44fab1911775a49636d0ce85333b634Zonr Changimport java.io.PrintWriter; 5337b74a387bb3993387029859c2d9d051c41c724eStephen Hinesimport java.util.ArrayList; 54affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 55affc150dc44fab1911775a49636d0ce85333b634Zonr Changpublic class TaskStack implements DimLayer.DimLayerUser, 56affc150dc44fab1911775a49636d0ce85333b634Zonr Chang BoundsAnimationController.AnimateBoundsUser { 5737b74a387bb3993387029859c2d9d051c41c724eStephen Hines /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to 58affc150dc44fab1911775a49636d0ce85333b634Zonr Chang * restrict IME adjustment so that a min portion of top stack remains visible.*/ 59affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f; 6022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao 61affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /** Dimming amount for non-focused stack when stacks are IME-adjusted. */ 62affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private static final float IME_ADJUST_DIM_AMOUNT = 0.25f; 63affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 64affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /** Unique identifier */ 6537b74a387bb3993387029859c2d9d051c41c724eStephen Hines final int mStackId; 6637b74a387bb3993387029859c2d9d051c41c724eStephen Hines 6737b74a387bb3993387029859c2d9d051c41c724eStephen Hines /** The service */ 68affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private final WindowManagerService mService; 69affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 70affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /** The display this stack sits under. */ 7137b74a387bb3993387029859c2d9d051c41c724eStephen Hines private DisplayContent mDisplayContent; 7237b74a387bb3993387029859c2d9d051c41c724eStephen Hines 73affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match 7437b74a387bb3993387029859c2d9d051c41c724eStephen Hines * mTaskHistory in the ActivityStack with the same mStackId */ 75affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private final ArrayList<Task> mTasks = new ArrayList<>(); 7637b74a387bb3993387029859c2d9d051c41c724eStephen Hines 77affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /** For comparison with DisplayContent bounds. */ 7837b74a387bb3993387029859c2d9d051c41c724eStephen Hines private Rect mTmpRect = new Rect(); 79affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private Rect mTmpRect2 = new Rect(); 8037b74a387bb3993387029859c2d9d051c41c724eStephen Hines 81affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /** Content limits relative to the DisplayContent this sits in. */ 8237b74a387bb3993387029859c2d9d051c41c724eStephen Hines private Rect mBounds = new Rect(); 83affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 8437b74a387bb3993387029859c2d9d051c41c724eStephen Hines /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */ 85affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private final Rect mAdjustedBounds = new Rect(); 86affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 87affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /** 8837b74a387bb3993387029859c2d9d051c41c724eStephen Hines * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they 89affc150dc44fab1911775a49636d0ce85333b634Zonr Chang * represent the state when the animation has ended. 9037b74a387bb3993387029859c2d9d051c41c724eStephen Hines */ 91affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private final Rect mFullyAdjustedImeBounds = new Rect(); 9237b74a387bb3993387029859c2d9d051c41c724eStephen Hines 93affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /** Whether mBounds is fullscreen */ 9437b74a387bb3993387029859c2d9d051c41c724eStephen Hines private boolean mFullscreen = true; 95affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 9637b74a387bb3993387029859c2d9d051c41c724eStephen Hines // Device rotation as of the last time {@link #mBounds} was set. 97affc150dc44fab1911775a49636d0ce85333b634Zonr Chang int mRotation; 98affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 99affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /** Density as of last time {@link #mBounds} was set. */ 10037b74a387bb3993387029859c2d9d051c41c724eStephen Hines int mDensity; 101affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 102affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */ 10322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao DimLayer mAnimationBackgroundSurface; 104affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 105affc150dc44fab1911775a49636d0ce85333b634Zonr Chang /** The particular window with an Animation with non-zero background color. */ 106affc150dc44fab1911775a49636d0ce85333b634Zonr Chang WindowStateAnimator mAnimationBackgroundAnimator; 107affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 10837b74a387bb3993387029859c2d9d051c41c724eStephen Hines /** Application tokens that are exiting, but still on screen for animations. */ 10937b74a387bb3993387029859c2d9d051c41c724eStephen Hines final AppTokenList mExitingAppTokens = new AppTokenList(); 11037b74a387bb3993387029859c2d9d051c41c724eStephen Hines 11137b74a387bb3993387029859c2d9d051c41c724eStephen Hines /** Detach this stack from its display when animation completes. */ 11237b74a387bb3993387029859c2d9d051c41c724eStephen Hines boolean mDeferDetach; 113affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 114affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // Display rotation as of the last time the display information was updated for this stack. 11537b74a387bb3993387029859c2d9d051c41c724eStephen Hines private int mLastUpdateDisplayInfoRotation = -1; 116affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // Display rotation as of the last time the configuration was updated for this stack. 117affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private int mLastConfigChangedRotation = -1; 118affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 119affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // Whether the stack and all its tasks is currently being drag-resized 120affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private boolean mDragResizing; 121affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 122affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private final Rect mTmpAdjustedBounds = new Rect(); 123affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private boolean mAdjustedForIme; 124affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private boolean mImeGoingAway; 12537b74a387bb3993387029859c2d9d051c41c724eStephen Hines private WindowState mImeWin; 126affc150dc44fab1911775a49636d0ce85333b634Zonr Chang private float mMinimizeAmount; 12737b74a387bb3993387029859c2d9d051c41c724eStephen Hines private float mAdjustImeAmount; 128 private float mAdjustDividerAmount; 129 private final int mDockedStackMinimizeThickness; 130 131 // If this is true, we are in the bounds animating mode. 132 // The task will be down or upscaled to perfectly fit the 133 // region it would have been cropped to. We may also avoid 134 // certain logic we would otherwise apply while resizing, 135 // while resizing in the bounds animating mode. 136 private boolean mBoundsAnimating = false; 137 // By default, movement animations are applied to all 138 // window movement. If this is true, animations will not 139 // be applied within this stack. This is useful for example 140 // if the windows are moving as the result of a stack animation, 141 // in which case a second window animation would cause jitter. 142 private boolean mFreezeMovementAnimations = false; 143 144 // Temporary storage for the new bounds that should be used after the configuration change. 145 // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration(). 146 private final Rect mBoundsAfterRotation = new Rect(); 147 148 TaskStack(WindowManagerService service, int stackId) { 149 mService = service; 150 mStackId = stackId; 151 mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize( 152 com.android.internal.R.dimen.docked_stack_minimize_thickness); 153 EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId); 154 } 155 156 DisplayContent getDisplayContent() { 157 return mDisplayContent; 158 } 159 160 ArrayList<Task> getTasks() { 161 return mTasks; 162 } 163 164 /** 165 * Set the bounds of the stack and its containing tasks. 166 * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen. 167 * @param configs Configuration for individual tasks, keyed by task id. 168 * @param taskBounds Bounds for individual tasks, keyed by task id. 169 * @return True if the stack bounds was changed. 170 * */ 171 boolean setBounds( 172 Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds, 173 SparseArray<Rect> taskTempInsetBounds) { 174 setBounds(stackBounds); 175 176 // Update bounds of containing tasks. 177 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 178 final Task task = mTasks.get(taskNdx); 179 Configuration config = configs.get(task.mTaskId); 180 if (config != null) { 181 Rect bounds = taskBounds.get(task.mTaskId); 182 if (task.isTwoFingerScrollMode()) { 183 // This is a non-resizeable task that's docked (or side-by-side to the docked 184 // stack). It might have been scrolled previously, and after the stack resizing, 185 // it might no longer fully cover the stack area. 186 // Save the old bounds and re-apply the scroll. This adjusts the bounds to 187 // fit the new stack bounds. 188 task.resizeLocked(bounds, config, false /* forced */); 189 task.getBounds(mTmpRect); 190 task.scrollLocked(mTmpRect); 191 } else { 192 task.resizeLocked(bounds, config, false /* forced */); 193 task.setTempInsetBounds( 194 taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId) 195 : null); 196 } 197 } else { 198 Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?"); 199 } 200 } 201 return true; 202 } 203 204 void prepareFreezingTaskBounds() { 205 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 206 final Task task = mTasks.get(taskNdx); 207 task.prepareFreezingBounds(); 208 } 209 } 210 211 boolean isFullscreenBounds(Rect bounds) { 212 if (mDisplayContent == null || bounds == null) { 213 return true; 214 } 215 mDisplayContent.getLogicalDisplayRect(mTmpRect); 216 return mTmpRect.equals(bounds); 217 } 218 219 /** 220 * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from 221 * the normal task bounds. 222 * 223 * @param bounds The adjusted bounds. 224 */ 225 private void setAdjustedBounds(Rect bounds) { 226 if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) { 227 return; 228 } 229 230 mAdjustedBounds.set(bounds); 231 final boolean adjusted = !mAdjustedBounds.isEmpty(); 232 Rect insetBounds = null; 233 if (adjusted && isAdjustedForMinimizedDock()) { 234 insetBounds = mBounds; 235 } else if (adjusted && isAdjustedForIme()) { 236 if (mImeGoingAway) { 237 insetBounds = mBounds; 238 } else { 239 insetBounds = mFullyAdjustedImeBounds; 240 } 241 } 242 alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds); 243 mDisplayContent.layoutNeeded = true; 244 } 245 246 private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) { 247 if (mFullscreen) { 248 return; 249 } 250 // Update bounds of containing tasks. 251 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 252 final Task task = mTasks.get(taskNdx); 253 if (task.isTwoFingerScrollMode()) { 254 // If we're scrolling we don't care about your bounds or configs, 255 // they should be null as if we were in fullscreen. 256 task.resizeLocked(null, null, false /* forced */); 257 task.getBounds(mTmpRect2); 258 task.scrollLocked(mTmpRect2); 259 } else if (task.isResizeable() && task.mOverrideConfig != Configuration.EMPTY) { 260 task.getBounds(mTmpRect2); 261 if (mAdjustedForIme && getDockSide() == DOCKED_TOP) { 262 int offsetY = adjustedBounds.bottom - mTmpRect2.bottom; 263 mTmpRect2.offset(0, offsetY); 264 } else { 265 mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top); 266 } 267 task.setTempInsetBounds(tempInsetBounds); 268 task.resizeLocked(mTmpRect2, task.mOverrideConfig, false /* forced */); 269 } 270 } 271 } 272 273 private boolean setBounds(Rect bounds) { 274 boolean oldFullscreen = mFullscreen; 275 int rotation = Surface.ROTATION_0; 276 int density = DENSITY_DPI_UNDEFINED; 277 if (mDisplayContent != null) { 278 mDisplayContent.getLogicalDisplayRect(mTmpRect); 279 rotation = mDisplayContent.getDisplayInfo().rotation; 280 density = mDisplayContent.getDisplayInfo().logicalDensityDpi; 281 mFullscreen = bounds == null; 282 if (mFullscreen) { 283 bounds = mTmpRect; 284 } 285 } 286 287 if (bounds == null) { 288 // Can't set to fullscreen if we don't have a display to get bounds from... 289 return false; 290 } 291 if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) { 292 return false; 293 } 294 295 if (mDisplayContent != null) { 296 mDisplayContent.mDimLayerController.updateDimLayer(this); 297 mAnimationBackgroundSurface.setBounds(bounds); 298 } 299 300 mBounds.set(bounds); 301 mRotation = rotation; 302 mDensity = density; 303 304 updateAdjustedBounds(); 305 306 return true; 307 } 308 309 /** Bounds of the stack without adjusting for other factors in the system like visibility 310 * of docked stack. 311 * Most callers should be using {@link #getBounds} as it take into consideration other system 312 * factors. */ 313 void getRawBounds(Rect out) { 314 out.set(mBounds); 315 } 316 317 /** Return true if the current bound can get outputted to the rest of the system as-is. */ 318 private boolean useCurrentBounds() { 319 if (mFullscreen 320 || !StackId.isResizeableByDockedStack(mStackId) 321 || mDisplayContent == null 322 || mDisplayContent.getDockedStackLocked() != null) { 323 return true; 324 } 325 return false; 326 } 327 328 public void getBounds(Rect out) { 329 if (useCurrentBounds()) { 330 // If we're currently adjusting for IME or minimized docked stack, we use the adjusted 331 // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked 332 // stack is visible since it is already what we want to represent to the rest of the 333 // system. 334 if (!mAdjustedBounds.isEmpty()) { 335 out.set(mAdjustedBounds); 336 } else { 337 out.set(mBounds); 338 } 339 return; 340 } 341 342 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack 343 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the 344 // system. 345 mDisplayContent.getLogicalDisplayRect(out); 346 } 347 348 /** Bounds of the stack with other system factors taken into consideration. */ 349 @Override 350 public void getDimBounds(Rect out) { 351 getBounds(out); 352 } 353 354 void updateDisplayInfo(Rect bounds) { 355 if (mDisplayContent == null) { 356 return; 357 } 358 359 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 360 mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent); 361 } 362 if (bounds != null) { 363 setBounds(bounds); 364 return; 365 } else if (mFullscreen) { 366 setBounds(null); 367 return; 368 } 369 370 mTmpRect2.set(mBounds); 371 final int newRotation = mDisplayContent.getDisplayInfo().rotation; 372 final int newDensity = mDisplayContent.getDisplayInfo().logicalDensityDpi; 373 if (mRotation == newRotation && mDensity == newDensity) { 374 setBounds(mTmpRect2); 375 } else { 376 mLastUpdateDisplayInfoRotation = newRotation; 377 updateBoundsAfterConfigChange(true); 378 } 379 } 380 381 boolean onConfigurationChanged() { 382 mLastConfigChangedRotation = getDisplayInfo().rotation; 383 return updateBoundsAfterConfigChange(false); 384 } 385 386 boolean updateBoundsAfterConfigChange(boolean scheduleResize) { 387 if (mLastConfigChangedRotation != mLastUpdateDisplayInfoRotation) { 388 // We wait for the rotation values after configuration change and display info. update 389 // to be equal before updating the bounds due to rotation change otherwise things might 390 // get out of alignment... 391 return false; 392 } 393 394 final int newRotation = getDisplayInfo().rotation; 395 final int newDensity = getDisplayInfo().logicalDensityDpi; 396 397 if (mRotation == newRotation && mDensity == newDensity) { 398 // Nothing to do here if the rotation didn't change 399 return false; 400 } 401 402 final int oldDockSide = mStackId == DOCKED_STACK_ID ? getDockSide() : DOCKED_INVALID; 403 mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2); 404 if (mStackId == DOCKED_STACK_ID) { 405 repositionDockedStackAfterRotation(mTmpRect2); 406 snapDockedStackAfterRotation(mTmpRect2); 407 final int newDockSide = getDockSide(mTmpRect2); 408 if (oldDockSide != newDockSide) { 409 mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide); 410 } 411 } 412 413 if (scheduleResize) { 414 // Post message to inform activity manager of the bounds change simulating 415 // a one-way call. We do this to prevent a deadlock between window manager 416 // lock and activity manager lock been held. 417 mService.mH.obtainMessage(RESIZE_STACK, mStackId, 418 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget(); 419 } else { 420 mBoundsAfterRotation.set(mTmpRect2); 421 } 422 423 return true; 424 } 425 426 void getBoundsForNewConfiguration(Rect outBounds) { 427 outBounds.set(mBoundsAfterRotation); 428 mBoundsAfterRotation.setEmpty(); 429 } 430 431 /** 432 * Some dock sides are not allowed by the policy. This method queries the policy and moves 433 * the docked stack around if needed. 434 * 435 * @param inOutBounds the bounds of the docked stack to adjust 436 */ 437 private void repositionDockedStackAfterRotation(Rect inOutBounds) { 438 int dockSide = getDockSide(inOutBounds); 439 if (mService.mPolicy.isDockSideAllowed(dockSide)) { 440 return; 441 } 442 mDisplayContent.getLogicalDisplayRect(mTmpRect); 443 dockSide = DockedDividerUtils.invertDockSide(dockSide); 444 switch (dockSide) { 445 case DOCKED_LEFT: 446 int movement = inOutBounds.left; 447 inOutBounds.left -= movement; 448 inOutBounds.right -= movement; 449 break; 450 case DOCKED_RIGHT: 451 movement = mTmpRect.right - inOutBounds.right; 452 inOutBounds.left += movement; 453 inOutBounds.right += movement; 454 break; 455 case DOCKED_TOP: 456 movement = inOutBounds.top; 457 inOutBounds.top -= movement; 458 inOutBounds.bottom -= movement; 459 break; 460 case DOCKED_BOTTOM: 461 movement = mTmpRect.bottom - inOutBounds.bottom; 462 inOutBounds.top += movement; 463 inOutBounds.bottom += movement; 464 break; 465 } 466 } 467 468 /** 469 * Snaps the bounds after rotation to the closest snap target for the docked stack. 470 */ 471 private void snapDockedStackAfterRotation(Rect outBounds) { 472 473 // Calculate the current position. 474 final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); 475 final int dividerSize = mService.getDefaultDisplayContentLocked() 476 .getDockedDividerController().getContentWidth(); 477 final int dockSide = getDockSide(outBounds); 478 final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds, 479 dockSide, dividerSize); 480 final int displayWidth = mDisplayContent.getDisplayInfo().logicalWidth; 481 final int displayHeight = mDisplayContent.getDisplayInfo().logicalHeight; 482 483 // Snap the position to a target. 484 final int rotation = displayInfo.rotation; 485 final int orientation = mService.mCurConfiguration.orientation; 486 mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds); 487 final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm( 488 mService.mContext.getResources(), displayWidth, displayHeight, 489 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds); 490 final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition); 491 492 // Recalculate the bounds based on the position of the target. 493 DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide, 494 outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight, 495 dividerSize); 496 } 497 498 boolean isAnimating() { 499 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 500 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; 501 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 502 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; 503 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 504 final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator; 505 if (winAnimator.isAnimating() || winAnimator.mWin.mAnimatingExit) { 506 return true; 507 } 508 } 509 } 510 } 511 return false; 512 } 513 514 void addTask(Task task, boolean toTop) { 515 addTask(task, toTop, task.showForAllUsers()); 516 } 517 518 /** 519 * Put a Task in this stack. Used for adding and moving. 520 * @param task The task to add. 521 * @param toTop Whether to add it to the top or bottom. 522 * @param showForAllUsers Whether to show the task regardless of the current user. 523 */ 524 void addTask(Task task, boolean toTop, boolean showForAllUsers) { 525 positionTask(task, toTop ? mTasks.size() : 0, showForAllUsers); 526 } 527 528 void positionTask(Task task, int position, boolean showForAllUsers) { 529 final boolean canShowTask = 530 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId); 531 mTasks.remove(task); 532 int stackSize = mTasks.size(); 533 int minPosition = 0; 534 int maxPosition = stackSize; 535 536 if (canShowTask) { 537 minPosition = computeMinPosition(minPosition, stackSize); 538 } else { 539 maxPosition = computeMaxPosition(maxPosition); 540 } 541 // Reset position based on minimum/maximum possible positions. 542 position = Math.min(Math.max(position, minPosition), maxPosition); 543 544 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, 545 "positionTask: task=" + task + " position=" + position); 546 mTasks.add(position, task); 547 548 // If we are moving the task across stacks, the scroll is no longer valid. 549 if (task.mStack != this) { 550 task.resetScrollLocked(); 551 } 552 task.mStack = this; 553 task.updateDisplayInfo(mDisplayContent); 554 boolean toTop = position == mTasks.size() - 1; 555 if (toTop) { 556 mDisplayContent.moveStack(this, true); 557 } 558 EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, position); 559 } 560 561 /** Calculate the minimum possible position for a task that can be shown to the user. 562 * The minimum position will be above all other tasks that can't be shown. 563 * @param minPosition The minimum position the caller is suggesting. 564 * We will start adjusting up from here. 565 * @param size The size of the current task list. 566 */ 567 private int computeMinPosition(int minPosition, int size) { 568 while (minPosition < size) { 569 final Task tmpTask = mTasks.get(minPosition); 570 final boolean canShowTmpTask = 571 tmpTask.showForAllUsers() 572 || mService.isCurrentProfileLocked(tmpTask.mUserId); 573 if (canShowTmpTask) { 574 break; 575 } 576 minPosition++; 577 } 578 return minPosition; 579 } 580 581 /** Calculate the maximum possible position for a task that can't be shown to the user. 582 * The maximum position will be below all other tasks that can be shown. 583 * @param maxPosition The maximum position the caller is suggesting. 584 * We will start adjusting down from here. 585 */ 586 private int computeMaxPosition(int maxPosition) { 587 while (maxPosition > 0) { 588 final Task tmpTask = mTasks.get(maxPosition - 1); 589 final boolean canShowTmpTask = 590 tmpTask.showForAllUsers() 591 || mService.isCurrentProfileLocked(tmpTask.mUserId); 592 if (!canShowTmpTask) { 593 break; 594 } 595 maxPosition--; 596 } 597 return maxPosition; 598 } 599 600 void moveTaskToTop(Task task) { 601 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToTop: task=" + task + " Callers=" 602 + Debug.getCallers(6)); 603 mTasks.remove(task); 604 addTask(task, true); 605 } 606 607 void moveTaskToBottom(Task task) { 608 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToBottom: task=" + task); 609 mTasks.remove(task); 610 addTask(task, false); 611 } 612 613 /** 614 * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the 615 * back. 616 * @param task The Task to delete. 617 */ 618 void removeTask(Task task) { 619 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeTask: task=" + task); 620 mTasks.remove(task); 621 if (mDisplayContent != null) { 622 if (mTasks.isEmpty()) { 623 mDisplayContent.moveStack(this, false); 624 } 625 mDisplayContent.layoutNeeded = true; 626 } 627 for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) { 628 final AppWindowToken wtoken = mExitingAppTokens.get(appNdx); 629 if (wtoken.mTask == task) { 630 wtoken.mIsExiting = false; 631 mExitingAppTokens.remove(appNdx); 632 } 633 } 634 } 635 636 void attachDisplayContent(DisplayContent displayContent) { 637 if (mDisplayContent != null) { 638 throw new IllegalStateException("attachDisplayContent: Already attached"); 639 } 640 641 mDisplayContent = displayContent; 642 mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(), 643 "animation background stackId=" + mStackId); 644 645 Rect bounds = null; 646 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID); 647 if (mStackId == DOCKED_STACK_ID 648 || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId))) { 649 // The existence of a docked stack affects the size of other static stack created since 650 // the docked stack occupies a dedicated region on screen. 651 bounds = new Rect(); 652 displayContent.getLogicalDisplayRect(mTmpRect); 653 mTmpRect2.setEmpty(); 654 if (dockedStack != null) { 655 dockedStack.getRawBounds(mTmpRect2); 656 } 657 final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode 658 == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; 659 getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2, 660 mDisplayContent.mDividerControllerLocked.getContentWidth(), 661 dockedOnTopOrLeft); 662 } 663 664 updateDisplayInfo(bounds); 665 } 666 667 void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) { 668 if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) 669 || mDisplayContent == null) { 670 outBounds.set(mBounds); 671 return; 672 } 673 674 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID); 675 if (dockedStack == null) { 676 // Not sure why you are calling this method when there is no docked stack... 677 throw new IllegalStateException( 678 "Calling getStackDockedModeBoundsLocked() when there is no docked stack."); 679 } 680 if (!ignoreVisibility && !dockedStack.isVisibleLocked()) { 681 // The docked stack is being dismissed, but we caught before it finished being 682 // dismissed. In that case we want to treat it as if it is not occupying any space and 683 // let others occupy the whole display. 684 mDisplayContent.getLogicalDisplayRect(outBounds); 685 return; 686 } 687 688 final int dockedSide = dockedStack.getDockSide(); 689 if (dockedSide == DOCKED_INVALID) { 690 // Not sure how you got here...Only thing we can do is return current bounds. 691 Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack); 692 outBounds.set(mBounds); 693 return; 694 } 695 696 mDisplayContent.getLogicalDisplayRect(mTmpRect); 697 dockedStack.getRawBounds(mTmpRect2); 698 final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT; 699 getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2, 700 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft); 701 702 } 703 704 /** 705 * Outputs the bounds a stack should be given the presence of a docked stack on the display. 706 * @param displayRect The bounds of the display the docked stack is on. 707 * @param outBounds Output bounds that should be used for the stack. 708 * @param stackId Id of stack we are calculating the bounds for. 709 * @param dockedBounds Bounds of the docked stack. 710 * @param dockDividerWidth We need to know the width of the divider make to the output bounds 711 * close to the side of the dock. 712 * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen. 713 */ 714 private void getStackDockedModeBounds( 715 Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth, 716 boolean dockOnTopOrLeft) { 717 final boolean dockedStack = stackId == DOCKED_STACK_ID; 718 final boolean splitHorizontally = displayRect.width() > displayRect.height(); 719 720 outBounds.set(displayRect); 721 if (dockedStack) { 722 if (mService.mDockedStackCreateBounds != null) { 723 outBounds.set(mService.mDockedStackCreateBounds); 724 return; 725 } 726 727 // The initial bounds of the docked stack when it is created about half the screen space 728 // and its bounds can be adjusted after that. The bounds of all other stacks are 729 // adjusted to occupy whatever screen space the docked stack isn't occupying. 730 final DisplayInfo di = mDisplayContent.getDisplayInfo(); 731 mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, 732 mTmpRect2); 733 final int position = new DividerSnapAlgorithm(mService.mContext.getResources(), 734 di.logicalWidth, 735 di.logicalHeight, 736 dockDividerWidth, 737 mService.mCurConfiguration.orientation == ORIENTATION_PORTRAIT, 738 mTmpRect2).getMiddleTarget().position; 739 740 if (dockOnTopOrLeft) { 741 if (splitHorizontally) { 742 outBounds.right = position; 743 } else { 744 outBounds.bottom = position; 745 } 746 } else { 747 if (splitHorizontally) { 748 outBounds.left = position + dockDividerWidth; 749 } else { 750 outBounds.top = position + dockDividerWidth; 751 } 752 } 753 return; 754 } 755 756 // Other stacks occupy whatever space is left by the docked stack. 757 if (!dockOnTopOrLeft) { 758 if (splitHorizontally) { 759 outBounds.right = dockedBounds.left - dockDividerWidth; 760 } else { 761 outBounds.bottom = dockedBounds.top - dockDividerWidth; 762 } 763 } else { 764 if (splitHorizontally) { 765 outBounds.left = dockedBounds.right + dockDividerWidth; 766 } else { 767 outBounds.top = dockedBounds.bottom + dockDividerWidth; 768 } 769 } 770 DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft); 771 } 772 773 void resetDockedStackToMiddle() { 774 if (mStackId != DOCKED_STACK_ID) { 775 throw new IllegalStateException("Not a docked stack=" + this); 776 } 777 778 mService.mDockedStackCreateBounds = null; 779 780 final Rect bounds = new Rect(); 781 getStackDockedModeBoundsLocked(bounds, true /*ignoreVisibility*/); 782 mService.mH.obtainMessage(RESIZE_STACK, DOCKED_STACK_ID, 783 1 /*allowResizeInDockedMode*/, bounds).sendToTarget(); 784 } 785 786 void detachDisplay() { 787 EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); 788 789 boolean doAnotherLayoutPass = false; 790 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 791 final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens; 792 for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) { 793 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows; 794 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) { 795 // We are in the middle of changing the state of displays/stacks/tasks. We need 796 // to finish that, before we let layout interfere with it. 797 mService.removeWindowLocked(appWindows.get(winNdx)); 798 doAnotherLayoutPass = true; 799 } 800 } 801 } 802 if (doAnotherLayoutPass) { 803 mService.mWindowPlacerLocked.requestTraversal(); 804 } 805 806 close(); 807 } 808 809 void resetAnimationBackgroundAnimator() { 810 mAnimationBackgroundAnimator = null; 811 mAnimationBackgroundSurface.hide(); 812 } 813 814 void setAnimationBackground(WindowStateAnimator winAnimator, int color) { 815 int animLayer = winAnimator.mAnimLayer; 816 if (mAnimationBackgroundAnimator == null 817 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) { 818 mAnimationBackgroundAnimator = winAnimator; 819 animLayer = mService.adjustAnimationBackground(winAnimator); 820 mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM, 821 ((color >> 24) & 0xff) / 255f, 0); 822 } 823 } 824 825 void switchUser() { 826 int top = mTasks.size(); 827 for (int taskNdx = 0; taskNdx < top; ++taskNdx) { 828 Task task = mTasks.get(taskNdx); 829 if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) { 830 mTasks.remove(taskNdx); 831 mTasks.add(task); 832 --top; 833 } 834 } 835 } 836 837 void close() { 838 if (mAnimationBackgroundSurface != null) { 839 mAnimationBackgroundSurface.destroySurface(); 840 mAnimationBackgroundSurface = null; 841 } 842 mDisplayContent = null; 843 } 844 845 /** 846 * Adjusts the stack bounds if the IME is visible. 847 * 848 * @param imeWin The IME window. 849 */ 850 void setAdjustedForIme(WindowState imeWin) { 851 mImeWin = imeWin; 852 mImeGoingAway = false; 853 if (!mAdjustedForIme) { 854 mAdjustedForIme = true; 855 mAdjustImeAmount = 0f; 856 mAdjustDividerAmount = 0f; 857 updateAdjustForIme(0f, 0f, true /* force */); 858 } 859 } 860 861 boolean isAdjustedForIme() { 862 return mAdjustedForIme || mImeGoingAway; 863 } 864 865 boolean isAnimatingForIme() { 866 return mImeWin != null && mImeWin.isAnimatingLw(); 867 } 868 869 /** 870 * Update the stack's bounds (crop or position) according to the IME window's 871 * current position. When IME window is animated, the bottom stack is animated 872 * together to track the IME window's current position, and the top stack is 873 * cropped as necessary. 874 * 875 * @return true if a traversal should be performed after the adjustment. 876 */ 877 boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) { 878 if (adjustAmount != mAdjustImeAmount 879 || adjustDividerAmount != mAdjustDividerAmount || force) { 880 mAdjustImeAmount = adjustAmount; 881 mAdjustDividerAmount = adjustDividerAmount; 882 updateAdjustedBounds(); 883 return isVisibleForUserLocked(); 884 } else { 885 return false; 886 } 887 } 888 889 /** 890 * Resets the adjustment after it got adjusted for the IME. 891 * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about 892 * animations; otherwise, set flag and animates the window away together 893 * with IME window. 894 */ 895 void resetAdjustedForIme(boolean adjustBoundsNow) { 896 if (adjustBoundsNow) { 897 mImeWin = null; 898 mAdjustedForIme = false; 899 mImeGoingAway = false; 900 mAdjustImeAmount = 0f; 901 mAdjustDividerAmount = 0f; 902 updateAdjustedBounds(); 903 mService.setResizeDimLayer(false, mStackId, 1.0f); 904 } else { 905 mImeGoingAway |= mAdjustedForIme; 906 } 907 } 908 909 /** 910 * Sets the amount how much we currently minimize our stack. 911 * 912 * @param minimizeAmount The amount, between 0 and 1. 913 * @return Whether the amount has changed and a layout is needed. 914 */ 915 boolean setAdjustedForMinimizedDock(float minimizeAmount) { 916 if (minimizeAmount != mMinimizeAmount) { 917 mMinimizeAmount = minimizeAmount; 918 updateAdjustedBounds(); 919 return isVisibleForUserLocked(); 920 } else { 921 return false; 922 } 923 } 924 925 boolean isAdjustedForMinimizedDock() { 926 return mMinimizeAmount != 0f; 927 } 928 929 /** 930 * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows 931 * to the list of to be drawn windows the service is waiting for. 932 */ 933 void beginImeAdjustAnimation() { 934 for (int j = mTasks.size() - 1; j >= 0; j--) { 935 final Task task = mTasks.get(j); 936 if (task.isVisibleForUser()) { 937 task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER); 938 task.addWindowsWaitingForDrawnIfResizingChanged(); 939 } 940 } 941 } 942 943 /** 944 * Resets the resizing state of all windows. 945 */ 946 void endImeAdjustAnimation() { 947 for (int j = mTasks.size() - 1; j >= 0; j--) { 948 mTasks.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER); 949 } 950 } 951 952 int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) { 953 return displayContentRect.top + (int) 954 ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN); 955 } 956 957 private boolean adjustForIME(final WindowState imeWin) { 958 final int dockedSide = getDockSide(); 959 final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM; 960 if (imeWin == null || !dockedTopOrBottom) { 961 return false; 962 } 963 964 final Rect displayContentRect = mTmpRect; 965 final Rect contentBounds = mTmpRect2; 966 967 // Calculate the content bounds excluding the area occupied by IME 968 getDisplayContent().getContentRect(displayContentRect); 969 contentBounds.set(displayContentRect); 970 int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top); 971 972 imeTop += imeWin.getGivenContentInsetsLw().top; 973 if (contentBounds.bottom > imeTop) { 974 contentBounds.bottom = imeTop; 975 } 976 977 final int yOffset = displayContentRect.bottom - contentBounds.bottom; 978 979 final int dividerWidth = 980 getDisplayContent().mDividerControllerLocked.getContentWidth(); 981 final int dividerWidthInactive = 982 getDisplayContent().mDividerControllerLocked.getContentWidthInactive(); 983 984 if (dockedSide == DOCKED_TOP) { 985 // If this stack is docked on top, we make it smaller so the bottom stack is not 986 // occluded by IME. We shift its bottom up by the height of the IME, but 987 // leaves at least 30% of the top stack visible. 988 final int minTopStackBottom = 989 getMinTopStackBottom(displayContentRect, mBounds.bottom); 990 final int bottom = Math.max( 991 mBounds.bottom - yOffset + dividerWidth - dividerWidthInactive, 992 minTopStackBottom); 993 mTmpAdjustedBounds.set(mBounds); 994 mTmpAdjustedBounds.bottom = 995 (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom); 996 mFullyAdjustedImeBounds.set(mBounds); 997 } else { 998 // When the stack is on bottom and has no focus, it's only adjusted for divider width. 999 final int dividerWidthDelta = dividerWidthInactive - dividerWidth; 1000 1001 // When the stack is on bottom and has focus, it needs to be moved up so as to 1002 // not occluded by IME, and at the same time adjusted for divider width. 1003 // We try to move it up by the height of the IME window, but only to the extent 1004 // that leaves at least 30% of the top stack visible. 1005 // 'top' is where the top of bottom stack will move to in this case. 1006 final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive; 1007 final int minTopStackBottom = 1008 getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth); 1009 final int top = Math.max( 1010 mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive); 1011 1012 mTmpAdjustedBounds.set(mBounds); 1013 // Account for the adjustment for IME and divider width separately. 1014 // (top - topBeforeImeAdjust) is the amount of movement due to IME only, 1015 // and dividerWidthDelta is due to divider width change only. 1016 mTmpAdjustedBounds.top = mBounds.top + 1017 (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) + 1018 mAdjustDividerAmount * dividerWidthDelta); 1019 mFullyAdjustedImeBounds.set(mBounds); 1020 mFullyAdjustedImeBounds.top = top; 1021 mFullyAdjustedImeBounds.bottom = top + mBounds.height(); 1022 } 1023 return true; 1024 } 1025 1026 private boolean adjustForMinimizedDockedStack(float minimizeAmount) { 1027 final int dockSide = getDockSide(); 1028 if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) { 1029 return false; 1030 } 1031 1032 if (dockSide == DOCKED_TOP) { 1033 mService.getStableInsetsLocked(mTmpRect); 1034 int topInset = mTmpRect.top; 1035 mTmpAdjustedBounds.set(mBounds); 1036 mTmpAdjustedBounds.bottom = 1037 (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom); 1038 } else if (dockSide == DOCKED_LEFT) { 1039 mTmpAdjustedBounds.set(mBounds); 1040 final int width = mBounds.width(); 1041 mTmpAdjustedBounds.right = 1042 (int) (minimizeAmount * mDockedStackMinimizeThickness 1043 + (1 - minimizeAmount) * mBounds.right); 1044 mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width; 1045 } else if (dockSide == DOCKED_RIGHT) { 1046 mTmpAdjustedBounds.set(mBounds); 1047 mTmpAdjustedBounds.left = 1048 (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness) 1049 + (1 - minimizeAmount) * mBounds.left); 1050 } 1051 return true; 1052 } 1053 1054 /** 1055 * @return the distance in pixels how much the stack gets minimized from it's original size 1056 */ 1057 int getMinimizeDistance() { 1058 final int dockSide = getDockSide(); 1059 if (dockSide == DOCKED_INVALID) { 1060 return 0; 1061 } 1062 1063 if (dockSide == DOCKED_TOP) { 1064 mService.getStableInsetsLocked(mTmpRect); 1065 int topInset = mTmpRect.top; 1066 return mBounds.bottom - topInset; 1067 } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) { 1068 return mBounds.width() - mDockedStackMinimizeThickness; 1069 } else { 1070 return 0; 1071 } 1072 } 1073 1074 /** 1075 * Updates the adjustment depending on it's current state. 1076 */ 1077 void updateAdjustedBounds() { 1078 boolean adjust = false; 1079 if (mMinimizeAmount != 0f) { 1080 adjust = adjustForMinimizedDockedStack(mMinimizeAmount); 1081 } else if (mAdjustedForIme) { 1082 adjust = adjustForIME(mImeWin); 1083 } 1084 if (!adjust) { 1085 mTmpAdjustedBounds.setEmpty(); 1086 } 1087 setAdjustedBounds(mTmpAdjustedBounds); 1088 1089 final boolean isImeTarget = (mService.getImeTargetStackLocked() == this); 1090 if (mAdjustedForIme && adjust && !isImeTarget) { 1091 final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount) 1092 * IME_ADJUST_DIM_AMOUNT; 1093 mService.setResizeDimLayer(true, mStackId, alpha); 1094 } 1095 } 1096 1097 boolean isAdjustedForMinimizedDockedStack() { 1098 return mMinimizeAmount != 0f; 1099 } 1100 1101 public void dump(String prefix, PrintWriter pw) { 1102 pw.println(prefix + "mStackId=" + mStackId); 1103 pw.println(prefix + "mDeferDetach=" + mDeferDetach); 1104 pw.println(prefix + "mFullscreen=" + mFullscreen); 1105 pw.println(prefix + "mBounds=" + mBounds.toShortString()); 1106 if (!mAdjustedBounds.isEmpty()) { 1107 pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString()); 1108 } 1109 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) { 1110 mTasks.get(taskNdx).dump(prefix + " ", pw); 1111 } 1112 if (mAnimationBackgroundSurface.isDimming()) { 1113 pw.println(prefix + "mWindowAnimationBackgroundSurface:"); 1114 mAnimationBackgroundSurface.printTo(prefix + " ", pw); 1115 } 1116 if (!mExitingAppTokens.isEmpty()) { 1117 pw.println(); 1118 pw.println(" Exiting application tokens:"); 1119 for (int i = mExitingAppTokens.size() - 1; i >= 0; i--) { 1120 WindowToken token = mExitingAppTokens.get(i); 1121 pw.print(" Exiting App #"); pw.print(i); 1122 pw.print(' '); pw.print(token); 1123 pw.println(':'); 1124 token.dump(pw, " "); 1125 } 1126 } 1127 } 1128 1129 /** Fullscreen status of the stack without adjusting for other factors in the system like 1130 * visibility of docked stack. 1131 * Most callers should be using {@link #isFullscreen} as it take into consideration other 1132 * system factors. */ 1133 boolean getRawFullscreen() { 1134 return mFullscreen; 1135 } 1136 1137 @Override 1138 public boolean isFullscreen() { 1139 if (useCurrentBounds()) { 1140 return mFullscreen; 1141 } 1142 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack 1143 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the 1144 // system. 1145 return true; 1146 } 1147 1148 @Override 1149 public DisplayInfo getDisplayInfo() { 1150 return mDisplayContent.getDisplayInfo(); 1151 } 1152 1153 @Override 1154 public String toString() { 1155 return "{stackId=" + mStackId + " tasks=" + mTasks + "}"; 1156 } 1157 1158 @Override 1159 public String toShortString() { 1160 return "Stack=" + mStackId; 1161 } 1162 1163 /** 1164 * For docked workspace (or workspace that's side-by-side to the docked), provides 1165 * information which side of the screen was the dock anchored. 1166 */ 1167 int getDockSide() { 1168 return getDockSide(mBounds); 1169 } 1170 1171 int getDockSide(Rect bounds) { 1172 if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) { 1173 return DOCKED_INVALID; 1174 } 1175 if (mDisplayContent == null) { 1176 return DOCKED_INVALID; 1177 } 1178 mDisplayContent.getLogicalDisplayRect(mTmpRect); 1179 final int orientation = mService.mCurConfiguration.orientation; 1180 if (orientation == Configuration.ORIENTATION_PORTRAIT) { 1181 // Portrait mode, docked either at the top or the bottom. 1182 if (bounds.top - mTmpRect.top <= mTmpRect.bottom - bounds.bottom) { 1183 return DOCKED_TOP; 1184 } else { 1185 return DOCKED_BOTTOM; 1186 } 1187 } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 1188 // Landscape mode, docked either on the left or on the right. 1189 if (bounds.left - mTmpRect.left <= mTmpRect.right - bounds.right) { 1190 return DOCKED_LEFT; 1191 } else { 1192 return DOCKED_RIGHT; 1193 } 1194 } else { 1195 return DOCKED_INVALID; 1196 } 1197 } 1198 1199 boolean isVisibleLocked() { 1200 final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded() 1201 && !mService.mAnimator.mKeyguardGoingAway; 1202 if (keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) { 1203 // The keyguard is showing and the stack shouldn't show on top of the keyguard. 1204 return false; 1205 } 1206 1207 for (int i = mTasks.size() - 1; i >= 0; i--) { 1208 final Task task = mTasks.get(i); 1209 for (int j = task.mAppTokens.size() - 1; j >= 0; j--) { 1210 if (!task.mAppTokens.get(j).hidden) { 1211 return true; 1212 } 1213 } 1214 } 1215 1216 return false; 1217 } 1218 1219 /** 1220 * @return true if a the stack is visible for the current in user, ignoring any other visibility 1221 * aspects, and false otherwise 1222 */ 1223 boolean isVisibleForUserLocked() { 1224 for (int i = mTasks.size() - 1; i >= 0; i--) { 1225 final Task task = mTasks.get(i); 1226 if (task.isVisibleForUser()) { 1227 return true; 1228 } 1229 } 1230 return false; 1231 } 1232 1233 boolean isDragResizing() { 1234 return mDragResizing; 1235 } 1236 1237 void setDragResizingLocked(boolean resizing) { 1238 if (mDragResizing == resizing) { 1239 return; 1240 } 1241 mDragResizing = resizing; 1242 for (int i = mTasks.size() - 1; i >= 0 ; i--) { 1243 mTasks.get(i).resetDragResizingChangeReported(); 1244 } 1245 } 1246 1247 @Override // AnimatesBounds 1248 public boolean setSize(Rect bounds) { 1249 synchronized (mService.mWindowMap) { 1250 if (mDisplayContent == null) { 1251 return false; 1252 } 1253 } 1254 try { 1255 mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false, -1); 1256 } catch (RemoteException e) { 1257 } 1258 return true; 1259 } 1260 1261 public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) { 1262 synchronized (mService.mWindowMap) { 1263 if (mDisplayContent == null) { 1264 return false; 1265 } 1266 if (mStackId != PINNED_STACK_ID) { 1267 Slog.w(TAG_WM, "Attempt to use pinned stack resize animation helper on" 1268 + "non pinned stack"); 1269 return false; 1270 } 1271 } 1272 try { 1273 mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds); 1274 } catch (RemoteException e) { 1275 // I don't believe you. 1276 } 1277 return true; 1278 } 1279 1280 void forceWindowsScaleable(boolean force) { 1281 SurfaceControl.openTransaction(); 1282 try { 1283 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 1284 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; 1285 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 1286 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; 1287 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 1288 final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator; 1289 if (winAnimator == null || !winAnimator.hasSurface()) { 1290 continue; 1291 } 1292 winAnimator.mSurfaceController.forceScaleableInTransaction(force); 1293 } 1294 } 1295 } 1296 } finally { 1297 SurfaceControl.closeTransaction(); 1298 } 1299 } 1300 1301 @Override // AnimatesBounds 1302 public void onAnimationStart() { 1303 synchronized (mService.mWindowMap) { 1304 // We force windows out of SCALING_MODE_FREEZE 1305 // so that we can continue to animate them 1306 // while a resize is pending. 1307 forceWindowsScaleable(true); 1308 mFreezeMovementAnimations = true; 1309 mBoundsAnimating = true; 1310 } 1311 } 1312 1313 @Override // AnimatesBounds 1314 public void onAnimationEnd() { 1315 synchronized (mService.mWindowMap) { 1316 mFreezeMovementAnimations = false; 1317 mBoundsAnimating = false; 1318 forceWindowsScaleable(false); 1319 mService.requestTraversal(); 1320 } 1321 if (mStackId == PINNED_STACK_ID) { 1322 try { 1323 mService.mActivityManager.notifyPinnedStackAnimationEnded(); 1324 } catch (RemoteException e) { 1325 // I don't believe you... 1326 } 1327 } 1328 } 1329 1330 @Override 1331 public void moveToFullscreen() { 1332 try { 1333 mService.mActivityManager.moveTasksToFullscreenStack(mStackId, true); 1334 } catch (RemoteException e) { 1335 e.printStackTrace(); 1336 } 1337 } 1338 1339 @Override 1340 public void getFullScreenBounds(Rect bounds) { 1341 getDisplayContent().getContentRect(bounds); 1342 } 1343 1344 public boolean getFreezeMovementAnimations() { 1345 return mFreezeMovementAnimations; 1346 } 1347 1348 public boolean getForceScaleToCrop() { 1349 return mBoundsAnimating; 1350 } 1351 1352 public boolean getBoundsAnimating() { 1353 return mBoundsAnimating; 1354 } 1355} 1356