/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.launcher3.states; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.res.Resources; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.UiThreadHelper; /** * Utility class to manage launcher rotation */ public class RotationHelper implements OnSharedPreferenceChangeListener { public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation"; public static boolean getAllowRotationDefaultValue() { // If the device was scaled, used the original dimensions to determine if rotation // is allowed of not. Resources res = Resources.getSystem(); int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp * res.getDisplayMetrics().densityDpi / DENSITY_DEVICE_STABLE; return originalSmallestWidth >= 600; } public static final int REQUEST_NONE = 0; public static final int REQUEST_ROTATE = 1; public static final int REQUEST_LOCK = 2; private final Launcher mLauncher; private final SharedPreferences mPrefs; private boolean mIgnoreAutoRotateSettings; private boolean mAutoRotateEnabled; /** * Rotation request made by {@link InternalStateHandler}. This supersedes any other request. */ private int mStateHandlerRequest = REQUEST_NONE; /** * Rotation request made by an app transition */ private int mCurrentTransitionRequest = REQUEST_NONE; /** * Rotation request made by a Launcher State */ private int mCurrentStateRequest = REQUEST_NONE; // This is used to defer setting rotation flags until the activity is being created private boolean mInitialized; private boolean mDestroyed; private boolean mRotationHasDifferentUI; private int mLastActivityFlags = -1; public RotationHelper(Launcher launcher) { mLauncher = launcher; // On large devices we do not handle auto-rotate differently. mIgnoreAutoRotateSettings = mLauncher.getResources().getBoolean(R.bool.allow_rotation); if (!mIgnoreAutoRotateSettings) { mPrefs = Utilities.getPrefs(mLauncher); mPrefs.registerOnSharedPreferenceChangeListener(this); mAutoRotateEnabled = mPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY, getAllowRotationDefaultValue()); } else { mPrefs = null; } } public void setRotationHadDifferentUI(boolean rotationHasDifferentUI) { mRotationHasDifferentUI = rotationHasDifferentUI; } public boolean homeScreenCanRotate() { return mRotationHasDifferentUI || mIgnoreAutoRotateSettings || mAutoRotateEnabled || mStateHandlerRequest != REQUEST_NONE || mLauncher.getDeviceProfile().isMultiWindowMode; } public void updateRotationAnimation() { if (FeatureFlags.FAKE_LANDSCAPE_UI.get()) { WindowManager.LayoutParams lp = mLauncher.getWindow().getAttributes(); int oldAnim = lp.rotationAnimation; lp.rotationAnimation = homeScreenCanRotate() ? WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE : WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS; if (oldAnim != lp.rotationAnimation) { mLauncher.getWindow().setAttributes(lp); } } } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { boolean wasRotationEnabled = mAutoRotateEnabled; mAutoRotateEnabled = mPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY, getAllowRotationDefaultValue()); if (mAutoRotateEnabled != wasRotationEnabled) { notifyChange(); updateRotationAnimation(); mLauncher.reapplyUi(); } } public void setStateHandlerRequest(int request) { if (mStateHandlerRequest != request) { mStateHandlerRequest = request; updateRotationAnimation(); notifyChange(); } } public void setCurrentTransitionRequest(int request) { if (mCurrentTransitionRequest != request) { mCurrentTransitionRequest = request; notifyChange(); } } public void setCurrentStateRequest(int request) { if (mCurrentStateRequest != request) { mCurrentStateRequest = request; notifyChange(); } } // Used by tests only. public void forceAllowRotationForTesting(boolean allowRotation) { mIgnoreAutoRotateSettings = allowRotation || mLauncher.getResources().getBoolean(R.bool.allow_rotation); notifyChange(); } public void initialize() { if (!mInitialized) { mInitialized = true; notifyChange(); updateRotationAnimation(); } } public void destroy() { if (!mDestroyed) { mDestroyed = true; if (mPrefs != null) { mPrefs.unregisterOnSharedPreferenceChangeListener(this); } } } private void notifyChange() { if (!mInitialized || mDestroyed) { return; } final int activityFlags; if (mStateHandlerRequest != REQUEST_NONE) { activityFlags = mStateHandlerRequest == REQUEST_LOCK ? SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED; } else if (mCurrentTransitionRequest != REQUEST_NONE) { activityFlags = mCurrentTransitionRequest == REQUEST_LOCK ? SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED; } else if (mCurrentStateRequest == REQUEST_LOCK) { activityFlags = SCREEN_ORIENTATION_LOCKED; } else if (mIgnoreAutoRotateSettings || mCurrentStateRequest == REQUEST_ROTATE || mAutoRotateEnabled) { activityFlags = SCREEN_ORIENTATION_UNSPECIFIED; } else { // If auto rotation is off, allow rotation on the activity, in case the user is using // forced rotation. activityFlags = SCREEN_ORIENTATION_NOSENSOR; } if (activityFlags != mLastActivityFlags) { mLastActivityFlags = activityFlags; UiThreadHelper.setOrientationAsync(mLauncher, activityFlags); } } @Override public String toString() { return String.format("[mStateHandlerRequest=%d, mCurrentStateRequest=%d," + " mLastActivityFlags=%d, mIgnoreAutoRotateSettings=%b, mAutoRotateEnabled=%b]", mStateHandlerRequest, mCurrentStateRequest, mLastActivityFlags, mIgnoreAutoRotateSettings, mAutoRotateEnabled); } }