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.server.dreams; 18 19 import static android.os.PowerManager.USER_ACTIVITY_EVENT_OTHER; 20 import static android.os.PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS; 21 22 import static org.mockito.ArgumentMatchers.anyInt; 23 import static org.mockito.ArgumentMatchers.anyLong; 24 import static org.mockito.ArgumentMatchers.anyString; 25 import static org.mockito.ArgumentMatchers.eq; 26 import static org.mockito.Mockito.any; 27 import static org.mockito.Mockito.clearInvocations; 28 import static org.mockito.Mockito.mock; 29 import static org.mockito.Mockito.verify; 30 import static org.mockito.Mockito.when; 31 32 import android.app.ActivityTaskManager; 33 import android.content.ComponentName; 34 import android.content.Context; 35 import android.content.ServiceConnection; 36 import android.os.Binder; 37 import android.os.Handler; 38 import android.os.IBinder; 39 import android.os.IPowerManager; 40 import android.os.IRemoteCallback; 41 import android.os.PowerManager; 42 import android.os.RemoteException; 43 import android.os.test.TestLooper; 44 import android.service.dreams.IDreamService; 45 46 import androidx.test.filters.SmallTest; 47 import androidx.test.runner.AndroidJUnit4; 48 49 import org.junit.Before; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.mockito.ArgumentCaptor; 53 import org.mockito.Captor; 54 import org.mockito.Mock; 55 import org.mockito.MockitoAnnotations; 56 57 @SmallTest 58 @RunWith(AndroidJUnit4.class) 59 public class DreamControllerTest { 60 @Mock 61 private DreamController.Listener mListener; 62 @Mock 63 private Context mContext; 64 65 @Mock 66 private ActivityTaskManager mActivityTaskManager; 67 @Mock 68 private IPowerManager mPowerManager; 69 70 @Mock 71 private IBinder mIBinder; 72 @Mock 73 private IDreamService mIDreamService; 74 75 @Captor 76 private ArgumentCaptor<ServiceConnection> mServiceConnectionACaptor; 77 @Captor 78 private ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor; 79 @Captor 80 private ArgumentCaptor<IRemoteCallback> mRemoteCallbackCaptor; 81 82 private final TestLooper mLooper = new TestLooper(); 83 private final Handler mHandler = new Handler(mLooper.getLooper()); 84 85 private DreamController mDreamController; 86 87 private Binder mToken; 88 private ComponentName mDreamName; 89 private ComponentName mOverlayName; 90 91 @Before setup()92 public void setup() { 93 MockitoAnnotations.initMocks(this); 94 95 when(mIDreamService.asBinder()).thenReturn(mIBinder); 96 when(mIBinder.queryLocalInterface(anyString())).thenReturn(mIDreamService); 97 when(mContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true); 98 when(mContext.getSystemService(Context.ACTIVITY_TASK_SERVICE)) 99 .thenReturn(mActivityTaskManager); 100 when(mContext.getSystemServiceName(ActivityTaskManager.class)) 101 .thenReturn(Context.ACTIVITY_TASK_SERVICE); 102 103 final PowerManager powerManager = new PowerManager(mContext, mPowerManager, null, null); 104 when(mContext.getSystemService(Context.POWER_SERVICE)) 105 .thenReturn(powerManager); 106 when(mContext.getSystemServiceName(PowerManager.class)) 107 .thenReturn(Context.POWER_SERVICE); 108 109 mToken = new Binder(); 110 mDreamName = ComponentName.unflattenFromString("dream"); 111 mOverlayName = ComponentName.unflattenFromString("dream_overlay"); 112 mDreamController = new DreamController(mContext, mHandler, mListener); 113 } 114 115 @Test startDream_attachOnServiceConnected()116 public void startDream_attachOnServiceConnected() throws RemoteException { 117 // Call dream controller to start dreaming. 118 mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, 119 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); 120 121 // Mock service connected. 122 final ServiceConnection serviceConnection = captureServiceConnection(); 123 serviceConnection.onServiceConnected(mDreamName, mIBinder); 124 mLooper.dispatchAll(); 125 126 // Verify that dream service is called to attach. 127 verify(mIDreamService).attach(eq(mToken), eq(false) /*doze*/, 128 eq(false) /*preview*/, any()); 129 } 130 131 @Test startDream_dreamListenerNotified()132 public void startDream_dreamListenerNotified() { 133 // Call dream controller to start dreaming. 134 mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, 135 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); 136 137 // Mock service connected. 138 final ServiceConnection serviceConnection = captureServiceConnection(); 139 serviceConnection.onServiceConnected(mDreamName, mIBinder); 140 mLooper.dispatchAll(); 141 142 // Verify that dream service is called to attach. 143 verify(mListener).onDreamStarted(any()); 144 } 145 146 @Test stopDream_dreamListenerNotified()147 public void stopDream_dreamListenerNotified() { 148 // Start dream. 149 mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, 150 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); 151 captureServiceConnection().onServiceConnected(mDreamName, mIBinder); 152 mLooper.dispatchAll(); 153 154 // Stop dream. 155 mDreamController.stopDream(true /*immediate*/, "test stop dream" /*reason*/); 156 mLooper.dispatchAll(); 157 158 // Verify that dream service is called to detach. 159 verify(mListener).onDreamStopped(any()); 160 } 161 162 @Test startDream_attachOnServiceConnectedInPreviewMode()163 public void startDream_attachOnServiceConnectedInPreviewMode() throws RemoteException { 164 // Call dream controller to start dreaming. 165 mDreamController.startDream(mToken, mDreamName, true /*isPreview*/, false /*doze*/, 166 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); 167 168 // Mock service connected. 169 final ServiceConnection serviceConnection = captureServiceConnection(); 170 serviceConnection.onServiceConnected(mDreamName, mIBinder); 171 mLooper.dispatchAll(); 172 173 // Verify that dream service is called to attach. 174 verify(mIDreamService).attach(eq(mToken), eq(false) /*doze*/, 175 eq(true) /*preview*/, any()); 176 } 177 178 @Test startDream_startASecondDream_detachOldDreamOnceNewDreamIsStarted()179 public void startDream_startASecondDream_detachOldDreamOnceNewDreamIsStarted() 180 throws RemoteException { 181 // Start first dream. 182 mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, 183 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); 184 captureServiceConnection().onServiceConnected(mDreamName, mIBinder); 185 mLooper.dispatchAll(); 186 clearInvocations(mContext); 187 188 // Set up second dream. 189 final Binder newToken = new Binder(); 190 final ComponentName newDreamName = ComponentName.unflattenFromString("new_dream"); 191 final ComponentName newOverlayName = ComponentName.unflattenFromString("new_dream_overlay"); 192 final IDreamService newDreamService = mock(IDreamService.class); 193 final IBinder newBinder = mock(IBinder.class); 194 when(newDreamService.asBinder()).thenReturn(newBinder); 195 when(newBinder.queryLocalInterface(anyString())).thenReturn(newDreamService); 196 197 // Start second dream. 198 mDreamController.startDream(newToken, newDreamName, false /*isPreview*/, false /*doze*/, 199 0 /*userId*/, null /*wakeLock*/, newOverlayName, "test" /*reason*/); 200 captureServiceConnection().onServiceConnected(newDreamName, newBinder); 201 mLooper.dispatchAll(); 202 203 // Mock second dream started. 204 verify(newDreamService).attach(eq(newToken), eq(false) /*doze*/, 205 eq(false) /*preview*/, mRemoteCallbackCaptor.capture()); 206 mRemoteCallbackCaptor.getValue().sendResult(null /*data*/); 207 mLooper.dispatchAll(); 208 209 // Verify that the first dream is called to detach. 210 verify(mIDreamService).detach(); 211 } 212 213 @Test stopDream_detachFromService()214 public void stopDream_detachFromService() throws RemoteException { 215 // Start dream. 216 mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, 217 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); 218 captureServiceConnection().onServiceConnected(mDreamName, mIBinder); 219 mLooper.dispatchAll(); 220 221 // Stop dream. 222 mDreamController.stopDream(true /*immediate*/, "test stop dream" /*reason*/); 223 224 // Verify that dream service is called to detach. 225 verify(mIDreamService).detach(); 226 } 227 228 @Test serviceDisconnect_resetsScreenTimeout()229 public void serviceDisconnect_resetsScreenTimeout() throws RemoteException { 230 // Start dream. 231 mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, 232 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); 233 ServiceConnection serviceConnection = captureServiceConnection(); 234 serviceConnection.onServiceConnected(mDreamName, mIBinder); 235 mLooper.dispatchAll(); 236 237 // Dream disconnects unexpectedly. 238 serviceConnection.onServiceDisconnected(mDreamName); 239 mLooper.dispatchAll(); 240 241 // Power manager receives user activity signal. 242 verify(mPowerManager).userActivity(/*displayId=*/ anyInt(), /*time=*/ anyLong(), 243 eq(USER_ACTIVITY_EVENT_OTHER), 244 eq(USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS)); 245 } 246 247 @Test binderDied_resetsScreenTimeout()248 public void binderDied_resetsScreenTimeout() throws RemoteException { 249 // Start dream. 250 mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, 251 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); 252 captureServiceConnection().onServiceConnected(mDreamName, mIBinder); 253 mLooper.dispatchAll(); 254 255 // Dream binder dies. 256 captureDeathRecipient().binderDied(); 257 mLooper.dispatchAll(); 258 259 // Power manager receives user activity signal. 260 verify(mPowerManager).userActivity(/*displayId=*/ anyInt(), /*time=*/ anyLong(), 261 eq(USER_ACTIVITY_EVENT_OTHER), 262 eq(USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS)); 263 } 264 captureServiceConnection()265 private ServiceConnection captureServiceConnection() { 266 verify(mContext).bindServiceAsUser(any(), mServiceConnectionACaptor.capture(), anyInt(), 267 any()); 268 return mServiceConnectionACaptor.getValue(); 269 } 270 captureDeathRecipient()271 private IBinder.DeathRecipient captureDeathRecipient() throws RemoteException { 272 verify(mIBinder).linkToDeath(mDeathRecipientCaptor.capture(), anyInt()); 273 return mDeathRecipientCaptor.getValue(); 274 } 275 } 276