| /* |
| * 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); |
| } |
| } |