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