1 /* 2 * Copyright (C) 2018 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 package com.android.launcher3.states; 17 18 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; 19 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; 20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 21 22 import android.content.SharedPreferences; 23 import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 24 25 import com.android.launcher3.BaseActivity; 26 import com.android.launcher3.DeviceProfile; 27 import com.android.launcher3.Utilities; 28 import com.android.launcher3.util.ActivityTracker; 29 import com.android.launcher3.util.UiThreadHelper; 30 31 /** 32 * Utility class to manage launcher rotation 33 */ 34 public class RotationHelper implements OnSharedPreferenceChangeListener, 35 DeviceProfile.OnDeviceProfileChangeListener { 36 37 private static final String TAG = "RotationHelper"; 38 39 public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation"; 40 41 public static final int REQUEST_NONE = 0; 42 public static final int REQUEST_ROTATE = 1; 43 public static final int REQUEST_LOCK = 2; 44 45 private BaseActivity mActivity; 46 private SharedPreferences mSharedPrefs = null; 47 48 private boolean mIgnoreAutoRotateSettings; 49 private boolean mForceAllowRotationForTesting; 50 private boolean mHomeRotationEnabled; 51 52 /** 53 * Rotation request made by 54 * {@link ActivityTracker.SchedulerCallback}. 55 * This supersedes any other request. 56 */ 57 private int mStateHandlerRequest = REQUEST_NONE; 58 /** 59 * Rotation request made by an app transition 60 */ 61 private int mCurrentTransitionRequest = REQUEST_NONE; 62 /** 63 * Rotation request made by a Launcher State 64 */ 65 private int mCurrentStateRequest = REQUEST_NONE; 66 67 // This is used to defer setting rotation flags until the activity is being created 68 private boolean mInitialized; 69 private boolean mDestroyed; 70 71 // Initialize mLastActivityFlags to a value not used by SCREEN_ORIENTATION flags 72 private int mLastActivityFlags = -999; 73 RotationHelper(BaseActivity activity)74 public RotationHelper(BaseActivity activity) { 75 mActivity = activity; 76 } 77 setIgnoreAutoRotateSettings(boolean ignoreAutoRotateSettings)78 private void setIgnoreAutoRotateSettings(boolean ignoreAutoRotateSettings) { 79 // On large devices we do not handle auto-rotate differently. 80 mIgnoreAutoRotateSettings = ignoreAutoRotateSettings; 81 if (!mIgnoreAutoRotateSettings) { 82 if (mSharedPrefs == null) { 83 mSharedPrefs = Utilities.getPrefs(mActivity); 84 mSharedPrefs.registerOnSharedPreferenceChangeListener(this); 85 } 86 mHomeRotationEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY, 87 mActivity.getDeviceProfile().allowRotation); 88 } else { 89 if (mSharedPrefs != null) { 90 mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this); 91 mSharedPrefs = null; 92 } 93 } 94 } 95 96 @Override onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s)97 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { 98 if (mDestroyed) return; 99 boolean wasRotationEnabled = mHomeRotationEnabled; 100 mHomeRotationEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY, 101 mActivity.getDeviceProfile().allowRotation); 102 if (mHomeRotationEnabled != wasRotationEnabled) { 103 notifyChange(); 104 } 105 } 106 107 @Override onDeviceProfileChanged(DeviceProfile dp)108 public void onDeviceProfileChanged(DeviceProfile dp) { 109 boolean ignoreAutoRotateSettings = dp.allowRotation; 110 if (mIgnoreAutoRotateSettings != ignoreAutoRotateSettings) { 111 setIgnoreAutoRotateSettings(ignoreAutoRotateSettings); 112 notifyChange(); 113 } 114 } 115 setStateHandlerRequest(int request)116 public void setStateHandlerRequest(int request) { 117 if (mStateHandlerRequest != request) { 118 mStateHandlerRequest = request; 119 notifyChange(); 120 } 121 } 122 setCurrentTransitionRequest(int request)123 public void setCurrentTransitionRequest(int request) { 124 if (mCurrentTransitionRequest != request) { 125 mCurrentTransitionRequest = request; 126 notifyChange(); 127 } 128 } 129 setCurrentStateRequest(int request)130 public void setCurrentStateRequest(int request) { 131 if (mCurrentStateRequest != request) { 132 mCurrentStateRequest = request; 133 notifyChange(); 134 } 135 } 136 137 // Used by tests only. forceAllowRotationForTesting(boolean allowRotation)138 public void forceAllowRotationForTesting(boolean allowRotation) { 139 mForceAllowRotationForTesting = allowRotation; 140 notifyChange(); 141 } 142 initialize()143 public void initialize() { 144 if (!mInitialized) { 145 mInitialized = true; 146 setIgnoreAutoRotateSettings(mActivity.getDeviceProfile().allowRotation); 147 mActivity.addOnDeviceProfileChangeListener(this); 148 notifyChange(); 149 } 150 } 151 destroy()152 public void destroy() { 153 if (!mDestroyed) { 154 mDestroyed = true; 155 mActivity.removeOnDeviceProfileChangeListener(this); 156 mActivity = null; 157 if (mSharedPrefs != null) { 158 mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this); 159 } 160 } 161 } 162 notifyChange()163 private void notifyChange() { 164 if (!mInitialized || mDestroyed) { 165 return; 166 } 167 168 final int activityFlags; 169 if (mStateHandlerRequest != REQUEST_NONE) { 170 activityFlags = mStateHandlerRequest == REQUEST_LOCK ? 171 SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED; 172 } else if (mCurrentTransitionRequest != REQUEST_NONE) { 173 activityFlags = mCurrentTransitionRequest == REQUEST_LOCK ? 174 SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED; 175 } else if (mCurrentStateRequest == REQUEST_LOCK) { 176 activityFlags = SCREEN_ORIENTATION_LOCKED; 177 } else if (mIgnoreAutoRotateSettings || mCurrentStateRequest == REQUEST_ROTATE 178 || mHomeRotationEnabled || mForceAllowRotationForTesting) { 179 activityFlags = SCREEN_ORIENTATION_UNSPECIFIED; 180 } else { 181 // If auto rotation is off, allow rotation on the activity, in case the user is using 182 // forced rotation. 183 activityFlags = SCREEN_ORIENTATION_NOSENSOR; 184 } 185 if (activityFlags != mLastActivityFlags) { 186 mLastActivityFlags = activityFlags; 187 UiThreadHelper.setOrientationAsync(mActivity, activityFlags); 188 } 189 } 190 191 /** 192 * @return how many factors {@param newRotation} is rotated 90 degrees clockwise. 193 * E.g. 1->Rotated by 90 degrees clockwise, 2->Rotated 180 clockwise... 194 * A value of 0 means no rotation has been applied 195 */ deltaRotation(int oldRotation, int newRotation)196 public static int deltaRotation(int oldRotation, int newRotation) { 197 int delta = newRotation - oldRotation; 198 if (delta < 0) delta += 4; 199 return delta; 200 } 201 202 @Override toString()203 public String toString() { 204 return String.format("[mStateHandlerRequest=%d, mCurrentStateRequest=%d, " 205 + "mLastActivityFlags=%d, mIgnoreAutoRotateSettings=%b, " 206 + "mHomeRotationEnabled=%b, mForceAllowRotationForTesting=%b]", 207 mStateHandlerRequest, mCurrentStateRequest, mLastActivityFlags, 208 mIgnoreAutoRotateSettings, mHomeRotationEnabled, mForceAllowRotationForTesting); 209 } 210 } 211