• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.settings.display;
18 
19 import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
20 import static android.provider.Settings.Secure.CAMERA_AUTOROTATE;
21 
22 import static com.android.settings.display.SmartAutoRotateController.hasSufficientPermission;
23 import static com.android.settings.display.SmartAutoRotateController.isRotationResolverServiceAvailable;
24 
25 import android.app.settings.SettingsEnums;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.hardware.SensorPrivacyManager;
31 import android.os.PowerManager;
32 import android.os.UserHandle;
33 import android.provider.Settings;
34 import android.text.TextUtils;
35 
36 import androidx.preference.Preference;
37 import androidx.preference.PreferenceScreen;
38 
39 import com.android.internal.annotations.VisibleForTesting;
40 import com.android.internal.view.RotationPolicy;
41 import com.android.settings.R;
42 import com.android.settings.core.TogglePreferenceController;
43 import com.android.settings.overlay.FeatureFactory;
44 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
45 import com.android.settingslib.core.lifecycle.LifecycleObserver;
46 import com.android.settingslib.core.lifecycle.events.OnStart;
47 import com.android.settingslib.core.lifecycle.events.OnStop;
48 
49 /**
50  * SmartAutoRotatePreferenceController provides auto rotate summary in display settings
51  */
52 public class SmartAutoRotatePreferenceController extends TogglePreferenceController
53         implements LifecycleObserver, OnStart, OnStop {
54 
55     private final MetricsFeatureProvider mMetricsFeatureProvider;
56     private final SensorPrivacyManager mPrivacyManager;
57     private final PowerManager mPowerManager;
58     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
59         @Override
60         public void onReceive(Context context, Intent intent) {
61             refreshSummary(mPreference);
62         }
63     };
64 
65     private RotationPolicy.RotationPolicyListener mRotationPolicyListener;
66     private Preference mPreference;
67 
SmartAutoRotatePreferenceController(Context context, String preferenceKey)68     public SmartAutoRotatePreferenceController(Context context, String preferenceKey) {
69         super(context, preferenceKey);
70         mPrivacyManager = SensorPrivacyManager.getInstance(context);
71         mPrivacyManager
72                 .addSensorPrivacyListener(CAMERA, (sensor, enabled) -> refreshSummary(mPreference));
73         mPowerManager = context.getSystemService(PowerManager.class);
74         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
75     }
76 
77     @Override
getAvailabilityStatus()78     public int getAvailabilityStatus() {
79         return RotationPolicy.isRotationLockToggleVisible(mContext)
80                 && !DeviceStateAutoRotationHelper.isDeviceStateRotationEnabled(mContext)
81                 ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
82     }
83 
84     @Override
isSliceable()85     public boolean isSliceable() {
86         return TextUtils.equals(getPreferenceKey(), "auto_rotate");
87     }
88 
89     @Override
isPublicSlice()90     public boolean isPublicSlice() {
91         return true;
92     }
93 
94     @Override
getSliceHighlightMenuRes()95     public int getSliceHighlightMenuRes() {
96         return R.string.menu_key_display;
97     }
98 
99     @Override
displayPreference(PreferenceScreen screen)100     public void displayPreference(PreferenceScreen screen) {
101         super.displayPreference(screen);
102         mPreference = screen.findPreference(getPreferenceKey());
103     }
104 
105     @Override
updateState(Preference preference)106     public void updateState(Preference preference) {
107         super.updateState(preference);
108         refreshSummary(mPreference);
109     }
110 
111     @Override
onStart()112     public void onStart() {
113         mContext.registerReceiver(mReceiver,
114                 new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
115         if (mRotationPolicyListener == null) {
116             mRotationPolicyListener = new RotationPolicy.RotationPolicyListener() {
117                 @Override
118                 public void onChange() {
119                     if (mPreference != null) {
120                         updateState(mPreference);
121                     }
122                 }
123             };
124         }
125         RotationPolicy.registerRotationPolicyListener(mContext,
126                 mRotationPolicyListener);
127     }
128 
129     @Override
onStop()130     public void onStop() {
131         mContext.unregisterReceiver(mReceiver);
132         if (mRotationPolicyListener != null) {
133             RotationPolicy.unregisterRotationPolicyListener(mContext,
134                     mRotationPolicyListener);
135         }
136     }
137 
138     /**
139      * Need this because all controller tests use Roboelectric. No easy way to mock this service,
140      * so we mock the call we need
141      */
142     @VisibleForTesting
isCameraLocked()143     boolean isCameraLocked() {
144         return mPrivacyManager.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA);
145     }
146 
147     @VisibleForTesting
isPowerSaveMode()148     boolean isPowerSaveMode() {
149         return mPowerManager.isPowerSaveMode();
150     }
151 
152     @Override
isChecked()153     public boolean isChecked() {
154         return !RotationPolicy.isRotationLocked(mContext);
155     }
156 
157     @Override
setChecked(boolean isChecked)158     public boolean setChecked(boolean isChecked) {
159         final boolean isLocked = !isChecked;
160         mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_ROTATION_LOCK,
161                 isLocked);
162         RotationPolicy.setRotationLock(mContext, isLocked);
163         return true;
164     }
165 
166     @Override
getSummary()167     public CharSequence getSummary() {
168         int activeStringId = R.string.auto_rotate_option_off;
169         if (!RotationPolicy.isRotationLocked(mContext)) {
170             final int cameraRotate = Settings.Secure.getIntForUser(
171                     mContext.getContentResolver(),
172                     CAMERA_AUTOROTATE,
173                     0, UserHandle.USER_CURRENT);
174             activeStringId = cameraRotate == 1 && isRotationResolverServiceAvailable(mContext)
175                     && hasSufficientPermission(mContext)
176                     && !isCameraLocked()
177                     && !isPowerSaveMode()
178                     ? R.string.auto_rotate_option_face_based
179                     : R.string.auto_rotate_option_on;
180         }
181         return mContext.getString(activeStringId);
182     }
183 }