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