1 /*
2  * Copyright (C) 2017 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.volume;
18 
19 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.times;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.when;
27 
28 import android.app.ActivityManager;
29 import android.app.KeyguardManager;
30 import android.app.NotificationManager;
31 import android.content.BroadcastReceiver;
32 import android.content.Context;
33 import android.content.IntentFilter;
34 import android.content.pm.PackageManager;
35 import android.media.AudioManager;
36 import android.media.IAudioService;
37 import android.media.session.MediaSession;
38 import android.os.Handler;
39 import android.os.Process;
40 import android.testing.AndroidTestingRunner;
41 import android.testing.TestableLooper;
42 import android.view.accessibility.AccessibilityManager;
43 
44 import androidx.test.filters.SmallTest;
45 
46 import com.android.systemui.SysuiTestCase;
47 import com.android.systemui.broadcast.BroadcastDispatcher;
48 import com.android.systemui.dump.DumpManager;
49 import com.android.systemui.keyguard.WakefulnessLifecycle;
50 import com.android.systemui.settings.UserTracker;
51 import com.android.systemui.statusbar.VibratorHelper;
52 import com.android.systemui.util.RingerModeLiveData;
53 import com.android.systemui.util.RingerModeTracker;
54 import com.android.systemui.util.concurrency.FakeExecutor;
55 import com.android.systemui.util.concurrency.FakeThreadFactory;
56 import com.android.systemui.util.concurrency.ThreadFactory;
57 import com.android.systemui.util.time.FakeSystemClock;
58 
59 import org.junit.Before;
60 import org.junit.Test;
61 import org.junit.runner.RunWith;
62 import org.mockito.ArgumentCaptor;
63 import org.mockito.Mock;
64 import org.mockito.MockitoAnnotations;
65 
66 import java.util.concurrent.Executor;
67 
68 @RunWith(AndroidTestingRunner.class)
69 @SmallTest
70 @TestableLooper.RunWithLooper
71 public class VolumeDialogControllerImplTest extends SysuiTestCase {
72 
73     TestableVolumeDialogControllerImpl mVolumeController;
74     VolumeDialogControllerImpl.C mCallback;
75     @Mock
76     private BroadcastDispatcher mBroadcastDispatcher;
77     @Mock
78     private RingerModeTracker mRingerModeTracker;
79     @Mock
80     private RingerModeLiveData mRingerModeLiveData;
81     @Mock
82     private RingerModeLiveData mRingerModeInternalLiveData;
83     private final FakeThreadFactory mThreadFactory = new FakeThreadFactory(
84             new FakeExecutor(new FakeSystemClock()));
85     @Mock
86     private AudioManager mAudioManager;
87     @Mock
88     private NotificationManager mNotificationManager;
89     @Mock
90     private VibratorHelper mVibrator;
91     @Mock
92     private IAudioService mIAudioService;
93     @Mock
94     private AccessibilityManager mAccessibilityManager;
95     @Mock
96     private PackageManager mPackageManager;
97     @Mock
98     private WakefulnessLifecycle mWakefullnessLifcycle;
99     @Mock
100     private KeyguardManager mKeyguardManager;
101     @Mock
102     private ActivityManager mActivityManager;
103     @Mock
104     private UserTracker mUserTracker;
105     @Mock
106     private DumpManager mDumpManager;
107 
108 
109     @Before
setup()110     public void setup() throws Exception {
111         MockitoAnnotations.initMocks(this);
112 
113         when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
114         when(mRingerModeTracker.getRingerModeInternal()).thenReturn(mRingerModeInternalLiveData);
115         // Initial non-set value
116         when(mRingerModeLiveData.getValue()).thenReturn(-1);
117         when(mRingerModeInternalLiveData.getValue()).thenReturn(-1);
118         when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
119         when(mUserTracker.getUserContext()).thenReturn(mContext);
120         // Enable group volume adjustments
121         mContext.getOrCreateTestableResources().addOverride(
122                 com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions,
123                 true);
124 
125         mCallback = mock(VolumeDialogControllerImpl.C.class);
126         mThreadFactory.setLooper(TestableLooper.get(this).getLooper());
127         mVolumeController = new TestableVolumeDialogControllerImpl(mContext,
128                 mBroadcastDispatcher, mRingerModeTracker, mThreadFactory, mAudioManager,
129                 mNotificationManager, mVibrator, mIAudioService, mAccessibilityManager,
130                 mPackageManager, mWakefullnessLifcycle, mKeyguardManager,
131                 mActivityManager, mUserTracker, mDumpManager, mCallback);
132         mVolumeController.setEnableDialogs(true, true);
133     }
134 
135     @Test
testRegisteredWithDispatcher()136     public void testRegisteredWithDispatcher() {
137         verify(mBroadcastDispatcher).registerReceiverWithHandler(any(BroadcastReceiver.class),
138                 any(IntentFilter.class),
139                 any(Handler.class)); // VolumeDialogControllerImpl does not call with user
140     }
141 
142     @Test
testVolumeChangeW_deviceNotInteractiveAOD()143     public void testVolumeChangeW_deviceNotInteractiveAOD() {
144         mVolumeController.setDeviceInteractive(false);
145         when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
146                 WakefulnessLifecycle.WAKEFULNESS_AWAKE);
147         mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
148         verify(mCallback, never()).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED, false,
149                 LOCK_TASK_MODE_NONE);
150     }
151 
152     @Test
testVolumeChangeW_deviceInteractive()153     public void testVolumeChangeW_deviceInteractive() {
154         mVolumeController.setDeviceInteractive(true);
155         when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
156                 WakefulnessLifecycle.WAKEFULNESS_AWAKE);
157         mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
158         verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED, false,
159                 LOCK_TASK_MODE_NONE);
160     }
161 
162     @Test
testVolumeChangeW_deviceInteractive_StartedSleeping()163     public void testVolumeChangeW_deviceInteractive_StartedSleeping() {
164         mVolumeController.setDeviceInteractive(true);
165         when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
166                 WakefulnessLifecycle.WAKEFULNESS_AWAKE);
167         mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
168         mVolumeController.setDeviceInteractive(false);
169         when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
170                 WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
171         mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
172         verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED, false,
173                 LOCK_TASK_MODE_NONE);
174     }
175 
176     @Test
testVolumeChangeW_deviceOutFromBLEHeadset_doStateChanged()177     public void testVolumeChangeW_deviceOutFromBLEHeadset_doStateChanged() {
178         mVolumeController.setDeviceInteractive(false);
179         when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
180                 WakefulnessLifecycle.WAKEFULNESS_AWAKE);
181         when(mAudioManager.getDevicesForStream(AudioManager.STREAM_VOICE_CALL)).thenReturn(
182                 AudioManager.DEVICE_OUT_BLE_HEADSET);
183 
184         mVolumeController.onVolumeChangedW(
185                 AudioManager.STREAM_VOICE_CALL, AudioManager.FLAG_SHOW_UI);
186 
187         verify(mCallback, times(1)).onStateChanged(any());
188     }
189 
190     @Test
testVolumeChangeW_deviceOutFromA2DP_doStateChanged()191     public void testVolumeChangeW_deviceOutFromA2DP_doStateChanged() {
192         mVolumeController.setDeviceInteractive(false);
193         when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
194                 WakefulnessLifecycle.WAKEFULNESS_AWAKE);
195         when(mAudioManager.getDevicesForStream(AudioManager.STREAM_VOICE_CALL)).thenReturn(
196                 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP);
197 
198         mVolumeController.onVolumeChangedW(
199                 AudioManager.STREAM_VOICE_CALL, AudioManager.FLAG_SHOW_UI);
200 
201         verify(mCallback, never()).onStateChanged(any());
202     }
203 
204     @Test
testOnRemoteVolumeChanged_newStream_noNullPointer()205     public void testOnRemoteVolumeChanged_newStream_noNullPointer() {
206         MediaSession.Token token = new MediaSession.Token(Process.myUid(), null);
207         mVolumeController.mMediaSessionsCallbacksW.onRemoteVolumeChanged(token, 0);
208     }
209 
210     @Test
testOnRemoteRemove_newStream_noNullPointer()211     public void testOnRemoteRemove_newStream_noNullPointer() {
212         MediaSession.Token token = new MediaSession.Token(Process.myUid(), null);
213         mVolumeController.mMediaSessionsCallbacksW.onRemoteRemoved(token);
214     }
215 
216     @Test
testRingerModeLiveDataObserving()217     public void testRingerModeLiveDataObserving() {
218         verify(mRingerModeLiveData).observeForever(any());
219         verify(mRingerModeInternalLiveData).observeForever(any());
220     }
221 
222     @Test
testAddCallbackWithUserTracker()223     public void testAddCallbackWithUserTracker() {
224         verify(mUserTracker).addCallback(any(UserTracker.Callback.class), any(Executor.class));
225     }
226 
227     static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
228         private final WakefulnessLifecycle.Observer mWakefullessLifecycleObserver;
229 
TestableVolumeDialogControllerImpl( Context context, BroadcastDispatcher broadcastDispatcher, RingerModeTracker ringerModeTracker, ThreadFactory theadFactory, AudioManager audioManager, NotificationManager notificationManager, VibratorHelper optionalVibrator, IAudioService iAudioService, AccessibilityManager accessibilityManager, PackageManager packageManager, WakefulnessLifecycle wakefulnessLifecycle, KeyguardManager keyguardManager, ActivityManager activityManager, UserTracker userTracker, DumpManager dumpManager, C callback)230         TestableVolumeDialogControllerImpl(
231                 Context context,
232                 BroadcastDispatcher broadcastDispatcher,
233                 RingerModeTracker ringerModeTracker,
234                 ThreadFactory theadFactory,
235                 AudioManager audioManager,
236                 NotificationManager notificationManager,
237                 VibratorHelper optionalVibrator,
238                 IAudioService iAudioService,
239                 AccessibilityManager accessibilityManager,
240                 PackageManager packageManager,
241                 WakefulnessLifecycle wakefulnessLifecycle,
242                 KeyguardManager keyguardManager,
243                 ActivityManager activityManager,
244                 UserTracker userTracker,
245                 DumpManager dumpManager,
246                 C callback) {
247             super(context, broadcastDispatcher, ringerModeTracker, theadFactory, audioManager,
248                     notificationManager, optionalVibrator, iAudioService, accessibilityManager,
249                     packageManager, wakefulnessLifecycle, keyguardManager,
250                     activityManager, userTracker, dumpManager);
251             mCallbacks = callback;
252 
253             ArgumentCaptor<WakefulnessLifecycle.Observer> observerCaptor =
254                     ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class);
255             verify(wakefulnessLifecycle).addObserver(observerCaptor.capture());
256             mWakefullessLifecycleObserver = observerCaptor.getValue();
257         }
258 
setDeviceInteractive(boolean interactive)259         public void setDeviceInteractive(boolean interactive) {
260             if (interactive) {
261                 mWakefullessLifecycleObserver.onStartedWakingUp();
262             } else {
263                 mWakefullessLifecycleObserver.onFinishedGoingToSleep();
264             }
265         }
266     }
267 
268 //    static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
269 //        TestableVolumeDialogControllerImpl(Context context, C callback,
270 //                BroadcastDispatcher broadcastDispatcher, RingerModeTracker ringerModeTracker,
271 //                ThreadFactory threadFactory) {
272 //            super(
273 //                    context, broadcastDispatcher,
274 //                    s == null ? Optional.empty() : Optional.of(() -> s), ringerModeTracker);
275 //            mCallbacks = callback;
276 //        }
277 //    }
278 
279 }
280