1 /* 2 * Copyright (C) 2022 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 junit.framework.TestCase.assertEquals; 20 import static junit.framework.TestCase.assertFalse; 21 import static junit.framework.TestCase.assertTrue; 22 23 import static org.mockito.ArgumentMatchers.any; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.spy; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.when; 28 29 import android.content.BroadcastReceiver; 30 import android.content.ComponentName; 31 import android.content.Intent; 32 import android.os.Handler; 33 import android.os.RemoteException; 34 import android.os.UserHandle; 35 import android.provider.Settings; 36 import android.service.dreams.IDreamManager; 37 import android.service.quicksettings.Tile; 38 import android.testing.AndroidTestingRunner; 39 import android.testing.TestableLooper; 40 41 import androidx.test.filters.SmallTest; 42 43 import com.android.internal.logging.MetricsLogger; 44 import com.android.systemui.R; 45 import com.android.systemui.SysuiTestCase; 46 import com.android.systemui.broadcast.BroadcastDispatcher; 47 import com.android.systemui.classifier.FalsingManagerFake; 48 import com.android.systemui.plugins.ActivityStarter; 49 import com.android.systemui.plugins.statusbar.StatusBarStateController; 50 import com.android.systemui.qs.QSHost; 51 import com.android.systemui.qs.logging.QSLogger; 52 import com.android.systemui.qs.tileimpl.QSTileImpl; 53 import com.android.systemui.settings.UserTracker; 54 import com.android.systemui.util.settings.FakeSettings; 55 import com.android.systemui.util.settings.SecureSettings; 56 57 import org.junit.After; 58 import org.junit.Before; 59 import org.junit.Test; 60 import org.junit.runner.RunWith; 61 import org.mockito.ArgumentCaptor; 62 import org.mockito.Mock; 63 import org.mockito.MockitoAnnotations; 64 65 @RunWith(AndroidTestingRunner.class) 66 @TestableLooper.RunWithLooper(setAsMainLooper = true) 67 @SmallTest 68 public class DreamTileTest extends SysuiTestCase { 69 70 @Mock 71 private ActivityStarter mActivityStarter; 72 @Mock 73 private QSHost mHost; 74 @Mock 75 private MetricsLogger mMetricsLogger; 76 @Mock 77 private QSLogger mQSLogger; 78 @Mock 79 private StatusBarStateController mStatusBarStateController; 80 @Mock 81 private IDreamManager mDreamManager; 82 @Mock 83 private BroadcastDispatcher mBroadcastDispatcher; 84 @Mock 85 private UserTracker mUserTracker; 86 87 private TestableLooper mTestableLooper; 88 89 private DreamTile mTile; 90 91 private SecureSettings mSecureSettings; 92 93 private static final ComponentName COLORS_DREAM_COMPONENT_NAME = new ComponentName( 94 "com.android.dreams", ".Colors"); 95 96 private static final int DEFAULT_USER = 0; 97 98 private final String mExpectedTileLabel = mContext.getResources().getString( 99 R.string.quick_settings_screensaver_label); 100 101 @Before setUp()102 public void setUp() throws Exception { 103 MockitoAnnotations.initMocks(this); 104 mSecureSettings = new FakeSettings(); 105 mTestableLooper = TestableLooper.get(this); 106 107 when(mHost.getUserId()).thenReturn(DEFAULT_USER); 108 when(mHost.getContext()).thenReturn(mContext); 109 110 mTile = spy(constructTileForTest(true, false)); 111 112 mTestableLooper.processAllMessages(); 113 mTile.initialize(); 114 } 115 116 @After tearDown()117 public void tearDown() { 118 mTile.destroy(); 119 mTestableLooper.processAllMessages(); 120 } 121 122 @Test testNotAvailable()123 public void testNotAvailable() throws RemoteException { 124 // Should not be available if screensaver is disabled 125 setScreensaverEnabled(false); 126 127 mTile.refreshState(); 128 mTestableLooper.processAllMessages(); 129 assertEquals(Tile.STATE_UNAVAILABLE, mTile.getState().state); 130 131 // Should not be available if component is not set 132 mSecureSettings.putInt(Settings.Secure.SCREENSAVER_ENABLED, 1); 133 when(mDreamManager.getDreamComponents()).thenReturn(null); 134 135 mTestableLooper.processAllMessages(); 136 assertEquals(Tile.STATE_UNAVAILABLE, mTile.getState().state); 137 assertEquals(mExpectedTileLabel, mTile.getState().contentDescription); 138 } 139 140 @Test testInactiveWhenDreaming()141 public void testInactiveWhenDreaming() throws RemoteException { 142 setScreensaverEnabled(true); 143 144 when(mDreamManager.getDreamComponents()).thenReturn(new ComponentName[]{ 145 COLORS_DREAM_COMPONENT_NAME 146 }); 147 when(mDreamManager.isDreaming()).thenReturn(false); 148 149 mTile.refreshState(); 150 mTestableLooper.processAllMessages(); 151 assertEquals(Tile.STATE_INACTIVE, mTile.getState().state); 152 } 153 154 @Test testActive()155 public void testActive() throws RemoteException { 156 setScreensaverEnabled(true); 157 158 when(mDreamManager.getDreamComponents()).thenReturn(new ComponentName[]{ 159 COLORS_DREAM_COMPONENT_NAME 160 }); 161 when(mDreamManager.isDreaming()).thenReturn(true); 162 163 mTile.refreshState(); 164 mTestableLooper.processAllMessages(); 165 assertEquals(Tile.STATE_ACTIVE, mTile.getState().state); 166 } 167 168 @Test testClick()169 public void testClick() throws RemoteException { 170 // Set the AOSP dream enabled as the base setup. 171 setScreensaverEnabled(true); 172 when(mDreamManager.getDreamComponents()).thenReturn(new ComponentName[]{ 173 COLORS_DREAM_COMPONENT_NAME 174 }); 175 when(mDreamManager.isDreaming()).thenReturn(false); 176 177 mTile.refreshState(); 178 mTestableLooper.processAllMessages(); 179 assertEquals(Tile.STATE_INACTIVE, mTile.getState().state); 180 181 // Now click 182 mTile.handleClick(null /* view */); 183 184 verify(mDreamManager).dream(); 185 186 when(mDreamManager.isDreaming()).thenReturn(true); 187 mTile.refreshState(); 188 mTestableLooper.processAllMessages(); 189 assertEquals(Tile.STATE_ACTIVE, mTile.getState().state); 190 191 // Click again to see that other method is called 192 mTile.handleClick(null /* view */); 193 194 verify(mDreamManager).awaken(); 195 } 196 197 @Test testContentDescription()198 public void testContentDescription() { 199 assertEquals(mExpectedTileLabel, mTile.getContentDescription(null)); 200 201 final String testDreamName = "MyDream"; 202 assertEquals(mExpectedTileLabel + ", " + testDreamName, 203 mTile.getContentDescription(testDreamName)); 204 } 205 206 @Test testUserAvailability()207 public void testUserAvailability() { 208 DreamTile unsupportedTile = constructTileForTest(false, true); 209 assertFalse(unsupportedTile.isAvailable()); 210 211 DreamTile supportedTileAllUsers = constructTileForTest(true, false); 212 213 UserHandle systemUserHandle = mock(UserHandle.class); 214 when(systemUserHandle.isSystem()).thenReturn(true); 215 216 UserHandle nonSystemUserHandle = mock(UserHandle.class); 217 when(nonSystemUserHandle.isSystem()).thenReturn(false); 218 219 when(mUserTracker.getUserHandle()).thenReturn(systemUserHandle); 220 assertTrue(supportedTileAllUsers.isAvailable()); 221 when(mUserTracker.getUserHandle()).thenReturn(nonSystemUserHandle); 222 assertTrue(supportedTileAllUsers.isAvailable()); 223 224 DreamTile supportedTileOnlySystemUser = constructTileForTest(true, true); 225 when(mUserTracker.getUserHandle()).thenReturn(systemUserHandle); 226 assertTrue(supportedTileOnlySystemUser.isAvailable()); 227 when(mUserTracker.getUserHandle()).thenReturn(nonSystemUserHandle); 228 assertFalse(supportedTileOnlySystemUser.isAvailable()); 229 } 230 231 @Test testIconDockState()232 public void testIconDockState() { 233 final DreamTile dockedTile = constructTileForTest(true, false); 234 235 final ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass( 236 BroadcastReceiver.class); 237 dockedTile.handleSetListening(true); 238 verify(mBroadcastDispatcher).registerReceiver(receiverCaptor.capture(), any()); 239 final BroadcastReceiver receiver = receiverCaptor.getValue(); 240 241 Intent dockIntent = new Intent(Intent.ACTION_DOCK_EVENT); 242 dockIntent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_DESK); 243 receiver.onReceive(mContext, dockIntent); 244 mTestableLooper.processAllMessages(); 245 assertEquals(QSTileImpl.ResourceIcon.get(R.drawable.ic_qs_screen_saver), 246 dockedTile.getState().icon); 247 248 dockIntent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); 249 receiver.onReceive(mContext, dockIntent); 250 mTestableLooper.processAllMessages(); 251 assertEquals(QSTileImpl.ResourceIcon.get(R.drawable.ic_qs_screen_saver_undocked), 252 dockedTile.getState().icon); 253 } 254 setScreensaverEnabled(boolean enabled)255 private void setScreensaverEnabled(boolean enabled) { 256 mSecureSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, enabled ? 1 : 0, 257 DEFAULT_USER); 258 } 259 constructTileForTest(boolean dreamSupported, boolean dreamOnlyEnabledForSystemUser)260 private DreamTile constructTileForTest(boolean dreamSupported, 261 boolean dreamOnlyEnabledForSystemUser) { 262 return new DreamTile( 263 mHost, 264 mTestableLooper.getLooper(), 265 new Handler(mTestableLooper.getLooper()), 266 new FalsingManagerFake(), 267 mMetricsLogger, 268 mStatusBarStateController, 269 mActivityStarter, 270 mQSLogger, 271 mDreamManager, 272 mSecureSettings, 273 mBroadcastDispatcher, 274 mUserTracker, 275 dreamSupported, dreamOnlyEnabledForSystemUser); 276 } 277 } 278