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.systemui.qs.tiles;
18 
19 import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
20 
21 import static junit.framework.TestCase.assertEquals;
22 
23 import static org.mockito.Mockito.doReturn;
24 import static org.mockito.Mockito.when;
25 
26 import android.Manifest;
27 import android.content.pm.PackageManager;
28 import android.hardware.SensorPrivacyManager;
29 import android.os.Handler;
30 import android.test.suitebuilder.annotation.SmallTest;
31 import android.testing.AndroidTestingRunner;
32 import android.testing.TestableLooper;
33 import android.testing.TestableResources;
34 
35 import com.android.internal.logging.MetricsLogger;
36 import com.android.systemui.R;
37 import com.android.systemui.SysuiTestCase;
38 import com.android.systemui.classifier.FalsingManagerFake;
39 import com.android.systemui.plugins.ActivityStarter;
40 import com.android.systemui.plugins.qs.QSTile;
41 import com.android.systemui.plugins.statusbar.StatusBarStateController;
42 import com.android.systemui.qs.QSHost;
43 import com.android.systemui.qs.QsEventLogger;
44 import com.android.systemui.qs.logging.QSLogger;
45 import com.android.systemui.qs.tileimpl.QSTileImpl;
46 import com.android.systemui.statusbar.policy.BatteryController;
47 import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController;
48 import com.android.systemui.statusbar.policy.RotationLockController;
49 import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
50 import com.android.systemui.util.settings.FakeSettings;
51 import com.android.systemui.util.wrapper.RotationPolicyWrapper;
52 
53 import org.junit.After;
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 import org.mockito.Mock;
58 import org.mockito.MockitoAnnotations;
59 
60 
61 @RunWith(AndroidTestingRunner.class)
62 @TestableLooper.RunWithLooper(setAsMainLooper = true)
63 @SmallTest
64 public class RotationLockTileTest extends SysuiTestCase {
65 
66     private static final String PACKAGE_NAME = "package_name";
67     private static final String[] DEFAULT_SETTINGS = new String[]{
68             "0:0",
69             "1:2"
70     };
71 
72     @Mock
73     private PackageManager mPackageManager;
74     @Mock
75     private ActivityStarter mActivityStarter;
76     @Mock
77     private QSHost mHost;
78     @Mock
79     private MetricsLogger mMetricsLogger;
80     @Mock
81     private StatusBarStateController mStatusBarStateController;
82     @Mock
83     private QSLogger mQSLogger;
84     @Mock
85     private SensorPrivacyManager mPrivacyManager;
86     @Mock
87     private BatteryController mBatteryController;
88     @Mock
89     DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
90     @Mock
91     RotationPolicyWrapper mRotationPolicyWrapper;
92     @Mock
93     QsEventLogger mUiEventLogger;
94 
95     private RotationLockController mController;
96     private TestableLooper mTestableLooper;
97     private RotationLockTile mLockTile;
98     private TestableResources mTestableResources;
99 
100     @Before
setUp()101     public void setUp() throws Exception {
102         MockitoAnnotations.initMocks(this);
103         mTestableLooper = TestableLooper.get(this);
104         mTestableResources = mContext.getOrCreateTestableResources();
105 
106         when(mHost.getContext()).thenReturn(mContext);
107         when(mHost.getUserContext()).thenReturn(mContext);
108         mTestableResources.addOverride(com.android.internal.R.bool.config_allowRotationResolver,
109                 true);
110 
111         mController = new RotationLockControllerImpl(mRotationPolicyWrapper,
112                 mDeviceStateRotationLockSettingController, DEFAULT_SETTINGS);
113 
114         mLockTile = new RotationLockTile(
115                 mHost,
116                 mUiEventLogger,
117                 mTestableLooper.getLooper(),
118                 new Handler(mTestableLooper.getLooper()),
119                 new FalsingManagerFake(),
120                 mMetricsLogger,
121                 mStatusBarStateController,
122                 mActivityStarter,
123                 mQSLogger,
124                 mController,
125                 mPrivacyManager,
126                 mBatteryController,
127                 new FakeSettings()
128         );
129 
130         mLockTile.initialize();
131 
132         // We are not setting the mocks to listening, so we trigger a first refresh state to
133         // set the initial state
134         mLockTile.refreshState();
135 
136         mTestableLooper.processAllMessages();
137 
138         mContext.setMockPackageManager(mPackageManager);
139         doReturn(PACKAGE_NAME).when(mPackageManager).getRotationResolverPackageName();
140         doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
141                 Manifest.permission.CAMERA, PACKAGE_NAME);
142 
143         when(mBatteryController.isPowerSave()).thenReturn(false);
144         when(mPrivacyManager.isSensorPrivacyEnabled(CAMERA)).thenReturn(false);
145         enableAutoRotation();
146         enableCameraBasedRotation();
147 
148         mLockTile.refreshState();
149         mTestableLooper.processAllMessages();
150     }
151 
152     @After
tearDown()153     public void tearDown() {
154         mLockTile.destroy();
155         mTestableLooper.processAllMessages();
156     }
157 
158     @Test
testSecondaryString_cameraRotateOn_returnsFaceBased()159     public void testSecondaryString_cameraRotateOn_returnsFaceBased() {
160         assertEquals(mContext.getString(R.string.rotation_lock_camera_rotation_on),
161                 mLockTile.getState().secondaryLabel.toString());
162     }
163 
164     @Test
testSecondaryString_rotateOff_isEmpty()165     public void testSecondaryString_rotateOff_isEmpty() {
166         disableAutoRotation();
167 
168         mLockTile.refreshState();
169         mTestableLooper.processAllMessages();
170 
171         assertEquals("", mLockTile.getState().secondaryLabel.toString());
172     }
173 
174     @Test
testSecondaryString_cameraRotateOff_isEmpty()175     public void testSecondaryString_cameraRotateOff_isEmpty() {
176         disableCameraBasedRotation();
177 
178         mLockTile.refreshState();
179         mTestableLooper.processAllMessages();
180 
181         assertEquals("", mLockTile.getState().secondaryLabel.toString());
182     }
183 
184     @Test
testSecondaryString_powerSaveEnabled_isEmpty()185     public void testSecondaryString_powerSaveEnabled_isEmpty() {
186         when(mBatteryController.isPowerSave()).thenReturn(true);
187 
188         mLockTile.refreshState();
189         mTestableLooper.processAllMessages();
190 
191         assertEquals("", mLockTile.getState().secondaryLabel.toString());
192     }
193 
194     @Test
testSecondaryString_cameraDisabled_isEmpty()195     public void testSecondaryString_cameraDisabled_isEmpty() {
196         when(mPrivacyManager.isSensorPrivacyEnabled(CAMERA)).thenReturn(true);
197 
198         mLockTile.refreshState();
199         mTestableLooper.processAllMessages();
200 
201         assertEquals("", mLockTile.getState().secondaryLabel.toString());
202     }
203 
204     @Test
testSecondaryString_noCameraPermission_isEmpty()205     public void testSecondaryString_noCameraPermission_isEmpty() {
206         doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
207                 Manifest.permission.CAMERA, PACKAGE_NAME);
208 
209         mLockTile.refreshState();
210         mTestableLooper.processAllMessages();
211 
212         assertEquals("", mLockTile.getState().secondaryLabel.toString());
213     }
214 
215     @Test
testSecondaryString_rotationResolverDisabled_isEmpty()216     public void testSecondaryString_rotationResolverDisabled_isEmpty() {
217         mTestableResources.addOverride(com.android.internal.R.bool.config_allowRotationResolver,
218                 false);
219         RotationLockTile otherTile = new RotationLockTile(
220                 mHost,
221                 mUiEventLogger,
222                 mTestableLooper.getLooper(),
223                 new Handler(mTestableLooper.getLooper()),
224                 new FalsingManagerFake(),
225                 mMetricsLogger,
226                 mStatusBarStateController,
227                 mActivityStarter,
228                 mQSLogger,
229                 mController,
230                 mPrivacyManager,
231                 mBatteryController,
232                 new FakeSettings()
233         );
234 
235         otherTile.refreshState();
236         mTestableLooper.processAllMessages();
237 
238         assertEquals("", otherTile.getState().secondaryLabel.toString());
239 
240         destroyTile(otherTile);
241     }
242 
243     @Test
testIcon_whenDisabled_isOffState()244     public void testIcon_whenDisabled_isOffState() {
245         QSTile.BooleanState state = new QSTile.BooleanState();
246         disableAutoRotation();
247 
248         mLockTile.handleUpdateState(state, /* arg= */ null);
249 
250         assertEquals(state.icon, QSTileImpl.ResourceIcon.get(R.drawable.qs_auto_rotate_icon_off));
251     }
252 
253     @Test
testIcon_whenEnabled_isOnState()254     public void testIcon_whenEnabled_isOnState() {
255         QSTile.BooleanState state = new QSTile.BooleanState();
256         enableAutoRotation();
257 
258         mLockTile.handleUpdateState(state, /* arg= */ null);
259 
260         assertEquals(state.icon, QSTileImpl.ResourceIcon.get(R.drawable.qs_auto_rotate_icon_on));
261     }
262 
263 
destroyTile(QSTileImpl<?> tile)264     private void destroyTile(QSTileImpl<?> tile) {
265         tile.destroy();
266         mTestableLooper.processAllMessages();
267     }
268 
enableAutoRotation()269     private void enableAutoRotation() {
270         when(mRotationPolicyWrapper.isRotationLocked()).thenReturn(false);
271     }
272 
disableAutoRotation()273     private void disableAutoRotation() {
274         when(mRotationPolicyWrapper.isRotationLocked()).thenReturn(true);
275     }
276 
enableCameraBasedRotation()277     private void enableCameraBasedRotation() {
278         when(mRotationPolicyWrapper.isCameraRotationEnabled()).thenReturn(true);
279     }
280 
disableCameraBasedRotation()281     private void disableCameraBasedRotation() {
282         when(mRotationPolicyWrapper.isCameraRotationEnabled()).thenReturn(false);
283     }
284 }
285