• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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