1 /* 2 * Copyright (C) 2020 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.quickstep.util; 18 19 import static android.view.OrientationEventListener.ORIENTATION_UNKNOWN; 20 import static android.view.Surface.ROTATION_0; 21 import static android.view.Surface.ROTATION_180; 22 import static android.view.Surface.ROTATION_270; 23 import static android.view.Surface.ROTATION_90; 24 25 import static com.android.launcher3.Flags.enableOverviewOnConnectedDisplays; 26 import static com.android.launcher3.LauncherPrefs.ALLOW_ROTATION; 27 import static com.android.launcher3.LauncherPrefs.FIXED_LANDSCAPE_MODE; 28 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; 29 import static com.android.launcher3.util.SettingsCache.ROTATION_SETTING_URI; 30 import static com.android.quickstep.BaseActivityInterface.getTaskDimension; 31 32 import static java.lang.annotation.RetentionPolicy.SOURCE; 33 34 import android.content.Context; 35 import android.graphics.Matrix; 36 import android.graphics.Point; 37 import android.graphics.PointF; 38 import android.graphics.Rect; 39 import android.util.Log; 40 import android.view.MotionEvent; 41 import android.view.OrientationEventListener; 42 import android.view.Surface; 43 44 import androidx.annotation.IntDef; 45 import androidx.annotation.NonNull; 46 47 import com.android.launcher3.DeviceProfile; 48 import com.android.launcher3.Flags; 49 import com.android.launcher3.InvariantDeviceProfile; 50 import com.android.launcher3.LauncherPrefChangeListener; 51 import com.android.launcher3.LauncherPrefs; 52 import com.android.launcher3.testing.shared.TestProtocol; 53 import com.android.launcher3.touch.PagedOrientationHandler; 54 import com.android.launcher3.util.DisplayController; 55 import com.android.launcher3.util.SettingsCache; 56 import com.android.quickstep.BaseContainerInterface; 57 import com.android.quickstep.SystemUiProxy; 58 import com.android.quickstep.TaskAnimationManager; 59 import com.android.quickstep.fallback.window.RecentsDisplayModel; 60 import com.android.quickstep.orientation.RecentsPagedOrientationHandler; 61 62 import java.lang.annotation.Retention; 63 import java.util.function.IntConsumer; 64 65 /** 66 * Container to hold orientation/rotation related information for Launcher. 67 * This is not meant to be an abstraction layer for applying different functionality between 68 * the different orientation/rotations. For that see {@link PagedOrientationHandler} 69 * 70 * This class has initial default state assuming the device and foreground app have 71 * no ({@link Surface#ROTATION_0} rotation. 72 */ 73 public class RecentsOrientedState implements LauncherPrefChangeListener { 74 75 private static final String TAG = "RecentsOrientedState"; 76 private static final boolean DEBUG = false; 77 78 @Retention(SOURCE) 79 @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270}) 80 public @interface SurfaceRotation {} 81 82 private RecentsPagedOrientationHandler mOrientationHandler = 83 RecentsPagedOrientationHandler.PORTRAIT; 84 85 private @SurfaceRotation int mTouchRotation = ROTATION_0; 86 private @SurfaceRotation int mDisplayRotation = ROTATION_0; 87 private @SurfaceRotation int mRecentsActivityRotation = ROTATION_0; 88 private @SurfaceRotation int mRecentsRotation = ROTATION_0 - 1; 89 90 // Launcher activity supports multiple orientation, but fallback activity does not 91 private static final int FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY = 1 << 0; 92 // Multiple orientation is only supported if density is < 600 93 private static final int FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY = 1 << 1; 94 // Shared prefs for rotation, only if activity supports it 95 private static final int FLAG_HOME_ROTATION_ALLOWED_IN_PREFS = 1 << 2; 96 // If the user has enabled system rotation 97 private static final int FLAG_SYSTEM_ROTATION_ALLOWED = 1 << 3; 98 // Multiple orientation is not supported in multiwindow mode 99 private static final int FLAG_MULTIWINDOW_ROTATION_ALLOWED = 1 << 4; 100 // Whether to rotation sensor is supported on the device 101 private static final int FLAG_ROTATION_WATCHER_SUPPORTED = 1 << 5; 102 // Whether to enable rotation watcher when multi-rotation is supported 103 private static final int FLAG_ROTATION_WATCHER_ENABLED = 1 << 6; 104 // Enable home rotation for UI tests, ignoring home rotation value from prefs 105 private static final int FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING = 1 << 7; 106 // Whether the swipe gesture is running, so the recents would stay locked in the 107 // current orientation 108 private static final int FLAG_SWIPE_UP_NOT_RUNNING = 1 << 8; 109 // Ignore shared prefs for home rotation rotation, allowing it in if the activity supports it 110 private static final int FLAG_IGNORE_ALLOW_HOME_ROTATION_PREF = 1 << 9; 111 112 // Shared prefs for fixed 90 degree rotation, activities should rotate if they support it 113 private static final int FLAG_HOME_FIXED_LANDSCAPE_PREFS = 1 << 10; 114 115 private static final int MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE = 116 FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY 117 | FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY; 118 119 // State for which rotation watcher will be enabled. We skip it when home rotation or 120 // multi-window is enabled as in that case, activity itself rotates. 121 private static final int VALUE_ROTATION_WATCHER_ENABLED = 122 MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE | FLAG_SYSTEM_ROTATION_ALLOWED 123 | FLAG_ROTATION_WATCHER_SUPPORTED | FLAG_ROTATION_WATCHER_ENABLED 124 | FLAG_SWIPE_UP_NOT_RUNNING; 125 126 private final Context mContext; 127 private final BaseContainerInterface mContainerInterface; 128 private final OrientationEventListener mOrientationListener; 129 private final SettingsCache mSettingsCache; 130 private final SettingsCache.OnChangeListener mRotationChangeListener = 131 isEnabled -> updateAutoRotateSetting(); 132 133 private final Matrix mTmpMatrix = new Matrix(); 134 135 private int mFlags; 136 private int mPreviousRotation = ROTATION_0; 137 private boolean mListenersInitialized = false; 138 139 // Combined int which encodes the full state. 140 private int mStateId = 0; 141 142 /** 143 * @param rotationChangeListener Callback for receiving rotation events when rotation watcher 144 * is enabled 145 * @see #setRotationWatcherEnabled(boolean) 146 */ RecentsOrientedState(Context context, BaseContainerInterface containerInterface, IntConsumer rotationChangeListener)147 public RecentsOrientedState(Context context, BaseContainerInterface containerInterface, 148 IntConsumer rotationChangeListener) { 149 mContext = context; 150 mContainerInterface = containerInterface; 151 mOrientationListener = new OrientationEventListener(context) { 152 @Override 153 public void onOrientationChanged(int degrees) { 154 int newRotation = getRotationForUserDegreesRotated(degrees, mPreviousRotation); 155 if (newRotation != mPreviousRotation) { 156 mPreviousRotation = newRotation; 157 rotationChangeListener.accept(newRotation); 158 } 159 } 160 }; 161 162 mFlags = mContainerInterface.rotationSupportedByActivity 163 ? FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY : 0; 164 165 mFlags |= FLAG_SWIPE_UP_NOT_RUNNING; 166 mSettingsCache = SettingsCache.INSTANCE.get(mContext); 167 initFlags(); 168 } 169 getContainerInterface()170 public BaseContainerInterface getContainerInterface() { 171 return mContainerInterface; 172 } 173 174 /** 175 * Sets the device profile for the current state. 176 */ setDeviceProfile(DeviceProfile deviceProfile)177 public void setDeviceProfile(DeviceProfile deviceProfile) { 178 boolean oldMultipleOrientationsSupported = isMultipleOrientationSupportedByDevice(); 179 setFlag(FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY, !deviceProfile.isTablet); 180 if (mListenersInitialized) { 181 boolean newMultipleOrientationsSupported = isMultipleOrientationSupportedByDevice(); 182 // If isMultipleOrientationSupportedByDevice is changed, init or destroy listeners 183 // accordingly. 184 if (newMultipleOrientationsSupported != oldMultipleOrientationsSupported) { 185 if (newMultipleOrientationsSupported) { 186 initMultipleOrientationListeners(); 187 } else { 188 destroyMultipleOrientationListeners(); 189 } 190 } 191 } 192 } 193 194 /** 195 * Sets the rotation for the recents activity, which could affect the appearance of task view. 196 * @see #update(int, int) 197 */ setRecentsRotation(@urfaceRotation int recentsRotation)198 public boolean setRecentsRotation(@SurfaceRotation int recentsRotation) { 199 mRecentsRotation = recentsRotation; 200 return updateHandler(); 201 } 202 203 /** 204 * Sets if the host is in multi-window mode 205 */ setMultiWindowMode(boolean isMultiWindow)206 public void setMultiWindowMode(boolean isMultiWindow) { 207 setFlag(FLAG_MULTIWINDOW_ROTATION_ALLOWED, isMultiWindow); 208 } 209 210 /** 211 * Sets if the swipe up gesture is currently running or not 212 */ setGestureActive(boolean isGestureActive)213 public boolean setGestureActive(boolean isGestureActive) { 214 return setFlag(FLAG_SWIPE_UP_NOT_RUNNING, !isGestureActive); 215 } 216 217 /** 218 * Sets the appropriate {@link PagedOrientationHandler} for {@link #mOrientationHandler} 219 * @param touchRotation The rotation the nav bar region that is touched is in 220 * @param displayRotation Rotation of the display/device 221 * 222 * @return true if there was any change in the internal state as a result of this call, 223 * false otherwise 224 */ update( @urfaceRotation int touchRotation, @SurfaceRotation int displayRotation)225 public boolean update( 226 @SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation) { 227 mDisplayRotation = displayRotation; 228 mTouchRotation = touchRotation; 229 mPreviousRotation = touchRotation; 230 return updateHandler(); 231 } 232 updateHandler()233 private boolean updateHandler() { 234 mRecentsActivityRotation = inferRecentsActivityRotation(mDisplayRotation); 235 if (mRecentsActivityRotation == mTouchRotation || shouldUseRealOrientation()) { 236 mOrientationHandler = RecentsPagedOrientationHandler.PORTRAIT; 237 } else if (mTouchRotation == ROTATION_90) { 238 mOrientationHandler = RecentsPagedOrientationHandler.LANDSCAPE; 239 } else if (mTouchRotation == ROTATION_270) { 240 mOrientationHandler = RecentsPagedOrientationHandler.SEASCAPE; 241 } else { 242 mOrientationHandler = RecentsPagedOrientationHandler.PORTRAIT; 243 } 244 if (DEBUG) { 245 Log.d(TAG, "current RecentsOrientedState: " + this); 246 } 247 248 int oldStateId = mStateId; 249 // Each SurfaceRotation value takes two bits 250 mStateId = (((((mFlags << 2) 251 | mDisplayRotation) << 2) 252 | mTouchRotation) << 3) 253 | (mRecentsRotation < 0 ? 7 : mRecentsRotation); 254 return mStateId != oldStateId; 255 } 256 shouldUseRealOrientation()257 private boolean shouldUseRealOrientation() { 258 return isRecentsActivityRotationAllowed() || isLauncherFixedLandscape(); 259 } 260 261 @SurfaceRotation inferRecentsActivityRotation(@urfaceRotation int displayRotation)262 private int inferRecentsActivityRotation(@SurfaceRotation int displayRotation) { 263 if (shouldUseRealOrientation()) { 264 return mRecentsRotation < 0 ? displayRotation : mRecentsRotation; 265 } else { 266 return ROTATION_0; 267 } 268 } 269 setFlag(int mask, boolean enabled)270 private boolean setFlag(int mask, boolean enabled) { 271 boolean wasRotationEnabled = !TestProtocol.sDisableSensorRotation 272 && (mFlags & VALUE_ROTATION_WATCHER_ENABLED) == VALUE_ROTATION_WATCHER_ENABLED 273 && !isRecentsActivityRotationAllowed(); 274 if (enabled) { 275 mFlags |= mask; 276 } else { 277 mFlags &= ~mask; 278 } 279 280 boolean isRotationEnabled = !TestProtocol.sDisableSensorRotation 281 && (mFlags & VALUE_ROTATION_WATCHER_ENABLED) == VALUE_ROTATION_WATCHER_ENABLED 282 && !isRecentsActivityRotationAllowed(); 283 if (wasRotationEnabled != isRotationEnabled) { 284 UI_HELPER_EXECUTOR.execute(() -> { 285 if (isRotationEnabled) { 286 mOrientationListener.enable(); 287 } else { 288 mOrientationListener.disable(); 289 } 290 }); 291 } 292 return updateHandler(); 293 } 294 295 @Override onPrefChanged(String s)296 public void onPrefChanged(String s) { 297 if (LauncherPrefs.ALLOW_ROTATION.getSharedPrefKey().equals(s)) { 298 updateHomeRotationSetting(); 299 } 300 if (LauncherPrefs.FIXED_LANDSCAPE_MODE.getSharedPrefKey().equals(s)) { 301 updateFixedLandscapeSetting(); 302 } 303 } 304 updateAutoRotateSetting()305 private void updateAutoRotateSetting() { 306 setFlag(FLAG_SYSTEM_ROTATION_ALLOWED, 307 mSettingsCache.getValue(ROTATION_SETTING_URI, 1)); 308 } 309 updateFixedLandscapeSetting()310 private void updateFixedLandscapeSetting() { 311 if (Flags.oneGridSpecs()) { 312 setFlag( 313 FLAG_HOME_FIXED_LANDSCAPE_PREFS, 314 LauncherPrefs.get(mContext).get(FIXED_LANDSCAPE_MODE) 315 ); 316 } 317 } 318 updateHomeRotationSetting()319 private void updateHomeRotationSetting() { 320 boolean homeRotationEnabled = LauncherPrefs.get(mContext).get(ALLOW_ROTATION); 321 setFlag(FLAG_HOME_ROTATION_ALLOWED_IN_PREFS, homeRotationEnabled); 322 SystemUiProxy.INSTANCE.get(mContext).setHomeRotationEnabled(homeRotationEnabled); 323 } 324 initFlags()325 private void initFlags() { 326 setFlag(FLAG_ROTATION_WATCHER_SUPPORTED, mOrientationListener.canDetectOrientation()); 327 328 // initialize external flags 329 updateAutoRotateSetting(); 330 updateHomeRotationSetting(); 331 updateFixedLandscapeSetting(); 332 } 333 initMultipleOrientationListeners()334 private void initMultipleOrientationListeners() { 335 LauncherPrefs.get(mContext).addListener(this, ALLOW_ROTATION); 336 mSettingsCache.register(ROTATION_SETTING_URI, mRotationChangeListener); 337 updateAutoRotateSetting(); 338 } 339 destroyMultipleOrientationListeners()340 private void destroyMultipleOrientationListeners() { 341 LauncherPrefs.get(mContext).removeListener(this, ALLOW_ROTATION); 342 mSettingsCache.unregister(ROTATION_SETTING_URI, mRotationChangeListener); 343 } 344 345 /** 346 * Initializes any system values and registers corresponding change listeners. It must be 347 * paired with {@link #destroyListeners()} call 348 */ initListeners()349 public void initListeners() { 350 mListenersInitialized = true; 351 if (isMultipleOrientationSupportedByDevice()) { 352 initMultipleOrientationListeners(); 353 } 354 initFlags(); 355 } 356 357 /** 358 * Unregisters any previously registered listeners. 359 */ destroyListeners()360 public void destroyListeners() { 361 mListenersInitialized = false; 362 if (isMultipleOrientationSupportedByDevice()) { 363 destroyMultipleOrientationListeners(); 364 } 365 setRotationWatcherEnabled(false); 366 } 367 forceAllowRotationForTesting(boolean forceAllow)368 public void forceAllowRotationForTesting(boolean forceAllow) { 369 setFlag(FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING, forceAllow); 370 } 371 372 @SurfaceRotation getDisplayRotation()373 public int getDisplayRotation() { 374 if (TaskAnimationManager.SHELL_TRANSITIONS_ROTATION) { 375 // When shell transitions are enabled, both the display and activity rotations should 376 // be the same once the gesture starts 377 return mRecentsActivityRotation; 378 } 379 return mDisplayRotation; 380 } 381 382 @SurfaceRotation getTouchRotation()383 public int getTouchRotation() { 384 return mTouchRotation; 385 } 386 387 @SurfaceRotation getRecentsActivityRotation()388 public int getRecentsActivityRotation() { 389 return mRecentsActivityRotation; 390 } 391 392 /** 393 * Returns an id that can be used to tracking internal changes 394 */ getStateId()395 public int getStateId() { 396 return mStateId; 397 } 398 isMultipleOrientationSupportedByDevice()399 public boolean isMultipleOrientationSupportedByDevice() { 400 return (mFlags & MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE) 401 == MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE; 402 } 403 ignoreAllowHomeRotationPreference()404 public void ignoreAllowHomeRotationPreference() { 405 setFlag(FLAG_IGNORE_ALLOW_HOME_ROTATION_PREF, true); 406 } 407 isLauncherFixedLandscape()408 public boolean isLauncherFixedLandscape() { 409 return (mFlags & FLAG_HOME_FIXED_LANDSCAPE_PREFS) == FLAG_HOME_FIXED_LANDSCAPE_PREFS; 410 } 411 isRecentsActivityRotationAllowed()412 public boolean isRecentsActivityRotationAllowed() { 413 // Activity rotation is allowed if the multi-simulated-rotation is not supported 414 // (fallback recents or tablets) or activity rotation is enabled by various settings. 415 return ((mFlags & MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE) 416 != MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE) 417 || (mFlags & (FLAG_IGNORE_ALLOW_HOME_ROTATION_PREF 418 | FLAG_HOME_ROTATION_ALLOWED_IN_PREFS 419 | FLAG_MULTIWINDOW_ROTATION_ALLOWED 420 | FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING)) != 0; 421 } 422 423 /** 424 * Enables or disables the rotation watcher for listening to rotation callbacks 425 */ setRotationWatcherEnabled(boolean isEnabled)426 public void setRotationWatcherEnabled(boolean isEnabled) { 427 setFlag(FLAG_ROTATION_WATCHER_ENABLED, isEnabled); 428 } 429 430 /** 431 * Returns the scale and pivot so that the provided taskRect can fit the provided full size 432 */ getFullScreenScaleAndPivot(Rect taskView, DeviceProfile dp, PointF outPivot)433 public float getFullScreenScaleAndPivot(Rect taskView, DeviceProfile dp, PointF outPivot) { 434 getTaskDimension(mContext, dp, outPivot); 435 float scale = Math.min(outPivot.x / taskView.width(), outPivot.y / taskView.height()); 436 if (scale == 1) { 437 outPivot.set(taskView.centerX(), taskView.centerY()); 438 } else { 439 float factor = scale / (scale - 1); 440 outPivot.set(taskView.left * factor, taskView.top * factor); 441 } 442 return scale; 443 } 444 getOrientationHandler()445 public RecentsPagedOrientationHandler getOrientationHandler() { 446 return mOrientationHandler; 447 } 448 449 /** 450 * For landscape, since the navbar is already in a vertical position, we don't have to do any 451 * rotations as the change in Y coordinate is what is read. We only flip the sign of the 452 * y coordinate to make it match existing behavior of swipe to the top to go previous 453 */ flipVertical(MotionEvent ev)454 public void flipVertical(MotionEvent ev) { 455 mTmpMatrix.setScale(1, -1); 456 ev.transform(mTmpMatrix); 457 } 458 459 /** 460 * Creates a matrix to transform the given motion event specified by degrees. 461 * If inverse is {@code true}, the inverse of that matrix will be applied 462 */ transformEvent(float degrees, MotionEvent ev, boolean inverse)463 public void transformEvent(float degrees, MotionEvent ev, boolean inverse) { 464 mTmpMatrix.setRotate(inverse ? -degrees : degrees); 465 ev.transform(mTmpMatrix); 466 467 // TODO: Add scaling back in based on degrees 468 /* 469 if (getWidth() > 0 && getHeight() > 0) { 470 float scale = ((float) getWidth()) / getHeight(); 471 transform.postScale(scale, 1 / scale); 472 } 473 */ 474 } 475 476 @SurfaceRotation getRotationForUserDegreesRotated(float degrees, int currentRotation)477 public static int getRotationForUserDegreesRotated(float degrees, int currentRotation) { 478 if (degrees == ORIENTATION_UNKNOWN) { 479 return currentRotation; 480 } 481 482 int threshold = 70; 483 switch (currentRotation) { 484 case ROTATION_0: 485 if (degrees > 180 && degrees < (360 - threshold)) { 486 return ROTATION_90; 487 } 488 if (degrees < 180 && degrees > threshold) { 489 return ROTATION_270; 490 } 491 break; 492 case ROTATION_270: 493 if (degrees < (90 - threshold) || 494 (degrees > (270 + threshold) && degrees < 360)) { 495 return ROTATION_0; 496 } 497 if (degrees > (90 + threshold) && degrees < 180) { 498 return ROTATION_180; 499 } 500 // flip from seascape to landscape 501 if (degrees > (180 + threshold) && degrees < 360) { 502 return ROTATION_90; 503 } 504 break; 505 case ROTATION_180: 506 if (degrees < (180 - threshold)) { 507 return ROTATION_270; 508 } 509 if (degrees > (180 + threshold)) { 510 return ROTATION_90; 511 } 512 break; 513 case ROTATION_90: 514 if (degrees < (270 - threshold) && degrees > 90) { 515 return ROTATION_180; 516 } 517 if (degrees > (270 + threshold) && degrees < 360 518 || (degrees >= 0 && degrees < threshold)) { 519 return ROTATION_0; 520 } 521 // flip from landscape to seascape 522 if (degrees > threshold && degrees < 180) { 523 return ROTATION_270; 524 } 525 break; 526 } 527 528 return currentRotation; 529 } 530 isDisplayPhoneNatural()531 public boolean isDisplayPhoneNatural() { 532 return mDisplayRotation == Surface.ROTATION_0 || mDisplayRotation == Surface.ROTATION_180; 533 } 534 535 /** 536 * Posts the transformation on the matrix representing the provided display rotation 537 */ postDisplayRotation(@urfaceRotation int displayRotation, float screenWidth, float screenHeight, Matrix out)538 public static void postDisplayRotation(@SurfaceRotation int displayRotation, 539 float screenWidth, float screenHeight, Matrix out) { 540 switch (displayRotation) { 541 case ROTATION_0: 542 return; 543 case ROTATION_90: 544 out.postRotate(270); 545 out.postTranslate(0, screenWidth); 546 break; 547 case ROTATION_180: 548 out.postRotate(180); 549 out.postTranslate(screenHeight, screenWidth); 550 break; 551 case ROTATION_270: 552 out.postRotate(90); 553 out.postTranslate(screenHeight, 0); 554 break; 555 } 556 } 557 558 /** 559 * Contrary to {@link #postDisplayRotation}. 560 */ preDisplayRotation(@urfaceRotation int displayRotation, float screenWidth, float screenHeight, Matrix out)561 public static void preDisplayRotation(@SurfaceRotation int displayRotation, 562 float screenWidth, float screenHeight, Matrix out) { 563 switch (displayRotation) { 564 case ROTATION_0: 565 return; 566 case ROTATION_90: 567 out.postRotate(90); 568 out.postTranslate(screenWidth, 0); 569 break; 570 case ROTATION_180: 571 out.postRotate(180); 572 out.postTranslate(screenHeight, screenWidth); 573 break; 574 case ROTATION_270: 575 out.postRotate(270); 576 out.postTranslate(0, screenHeight); 577 break; 578 } 579 } 580 581 @NonNull 582 @Override toString()583 public String toString() { 584 boolean systemRotationOn = (mFlags & FLAG_SYSTEM_ROTATION_ALLOWED) != 0; 585 return "[" 586 + "this=" + nameAndAddress(this) 587 + " mOrientationHandler=" + nameAndAddress(mOrientationHandler) 588 + " mDisplayRotation=" + mDisplayRotation 589 + " mTouchRotation=" + mTouchRotation 590 + " mRecentsActivityRotation=" + mRecentsActivityRotation 591 + " mRecentsRotation=" + mRecentsRotation 592 + " isRecentsActivityRotationAllowed=" + isRecentsActivityRotationAllowed() 593 + " mSystemRotation=" + systemRotationOn 594 + " mStateId=" + mStateId 595 + " mFlags=" + mFlags 596 + "]"; 597 } 598 599 /** 600 * Returns the device profile based on expected launcher rotation 601 */ getLauncherDeviceProfile(int displayId)602 public DeviceProfile getLauncherDeviceProfile(int displayId) { 603 if (enableOverviewOnConnectedDisplays()) { 604 return RecentsDisplayModel.getINSTANCE().get(mContext).getRecentsWindowManager( 605 displayId).getDeviceProfile(); 606 } else { 607 InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(mContext); 608 Point currentSize = DisplayController.INSTANCE.get(mContext).getInfo().currentSize; 609 610 int width, height; 611 if ((mRecentsActivityRotation == ROTATION_90 612 || mRecentsActivityRotation == ROTATION_270)) { 613 width = Math.max(currentSize.x, currentSize.y); 614 height = Math.min(currentSize.x, currentSize.y); 615 } else { 616 width = Math.min(currentSize.x, currentSize.y); 617 height = Math.max(currentSize.x, currentSize.y); 618 } 619 return idp.getBestMatch(width, height, mRecentsActivityRotation); 620 } 621 } 622 nameAndAddress(Object obj)623 private static String nameAndAddress(Object obj) { 624 return obj.getClass().getSimpleName() + "@" + obj.hashCode(); 625 } 626 } 627