1 /*
2  * Copyright 2018 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 package com.android.settings.connecteddevice;
17 
18 import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
19 import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static org.mockito.ArgumentMatchers.any;
24 import static org.mockito.ArgumentMatchers.anyString;
25 import static org.mockito.Mockito.doReturn;
26 import static org.mockito.Mockito.spy;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.content.Context;
31 import android.content.pm.PackageManager;
32 import android.media.AudioManager;
33 
34 import androidx.preference.Preference;
35 import androidx.preference.PreferenceGroup;
36 import androidx.preference.PreferenceManager;
37 import androidx.preference.PreferenceScreen;
38 
39 import com.android.settings.R;
40 import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater;
41 import com.android.settings.bluetooth.Utils;
42 import com.android.settings.dashboard.DashboardFragment;
43 import com.android.settings.testutils.shadow.ShadowAudioManager;
44 import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
45 import com.android.settingslib.bluetooth.BluetoothCallback;
46 import com.android.settingslib.bluetooth.BluetoothEventManager;
47 import com.android.settingslib.bluetooth.LocalBluetoothManager;
48 
49 import org.junit.After;
50 import org.junit.Before;
51 import org.junit.Test;
52 import org.junit.runner.RunWith;
53 import org.mockito.Answers;
54 import org.mockito.Mock;
55 import org.mockito.MockitoAnnotations;
56 import org.robolectric.RobolectricTestRunner;
57 import org.robolectric.RuntimeEnvironment;
58 import org.robolectric.annotation.Config;
59 
60 @RunWith(RobolectricTestRunner.class)
61 @Config(shadows = {ShadowAudioManager.class, ShadowBluetoothUtils.class})
62 public class AvailableMediaDeviceGroupControllerTest {
63 
64     private static final String PREFERENCE_KEY_1 = "pref_key_1";
65 
66     @Mock
67     private DashboardFragment mDashboardFragment;
68     @Mock
69     private AvailableMediaBluetoothDeviceUpdater mAvailableMediaBluetoothDeviceUpdater;
70     @Mock
71     private PreferenceScreen mPreferenceScreen;
72     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
73     private PreferenceManager mPreferenceManager;
74     @Mock
75     private PackageManager mPackageManager;
76     @Mock
77     private BluetoothEventManager mEventManager;
78     @Mock
79     private LocalBluetoothManager mLocalManager;
80 
81     private PreferenceGroup mPreferenceGroup;
82     private Context mContext;
83     private Preference mPreference;
84     private AvailableMediaDeviceGroupController mAvailableMediaDeviceGroupController;
85     private LocalBluetoothManager mLocalBluetoothManager;
86     private AudioManager mAudioManager;
87 
88     @Before
setUp()89     public void setUp() {
90         MockitoAnnotations.initMocks(this);
91 
92         mContext = spy(RuntimeEnvironment.application);
93         mPreference = new Preference(mContext);
94         mPreference.setKey(PREFERENCE_KEY_1);
95         mPreferenceGroup = spy(new PreferenceScreen(mContext, null));
96         when(mPreferenceGroup.getPreferenceManager()).thenReturn(mPreferenceManager);
97         doReturn(mContext).when(mDashboardFragment).getContext();
98         doReturn(mPackageManager).when(mContext).getPackageManager();
99         doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
100 
101         ShadowBluetoothUtils.sLocalBluetoothManager = mLocalManager;
102         mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
103         mAudioManager = mContext.getSystemService(AudioManager.class);
104         doReturn(mEventManager).when(mLocalBluetoothManager).getEventManager();
105 
106         mAvailableMediaDeviceGroupController = new AvailableMediaDeviceGroupController(mContext);
107         mAvailableMediaDeviceGroupController.
108                 setBluetoothDeviceUpdater(mAvailableMediaBluetoothDeviceUpdater);
109         mAvailableMediaDeviceGroupController.mPreferenceGroup = mPreferenceGroup;
110     }
111 
112     @After
tearDown()113     public void tearDown() {
114         ShadowBluetoothUtils.reset();
115     }
116 
117     @Test
onDeviceAdded_firstAdd_becomeVisibleAndPreferenceAdded()118     public void onDeviceAdded_firstAdd_becomeVisibleAndPreferenceAdded() {
119         mAvailableMediaDeviceGroupController.onDeviceAdded(mPreference);
120 
121         assertThat(mPreferenceGroup.isVisible()).isTrue();
122         assertThat((Preference) mPreferenceGroup.findPreference(PREFERENCE_KEY_1))
123                 .isEqualTo(mPreference);
124     }
125 
126     @Test
onDeviceRemoved_lastRemove_becomeInvisibleAndPreferenceRemoved()127     public void onDeviceRemoved_lastRemove_becomeInvisibleAndPreferenceRemoved() {
128         mPreferenceGroup.addPreference(mPreference);
129 
130         mAvailableMediaDeviceGroupController.onDeviceRemoved(mPreference);
131 
132         assertThat(mPreferenceGroup.isVisible()).isFalse();
133         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
134     }
135 
136     @Test
onDeviceRemoved_notLastRemove_stillVisible()137     public void onDeviceRemoved_notLastRemove_stillVisible() {
138         mPreferenceGroup.setVisible(true);
139         mPreferenceGroup.addPreference(mPreference);
140         mPreferenceGroup.addPreference(new Preference(mContext));
141 
142         mAvailableMediaDeviceGroupController.onDeviceRemoved(mPreference);
143 
144         assertThat(mPreferenceGroup.isVisible()).isTrue();
145     }
146 
147     @Test
displayPreference_becomeInvisible()148     public void displayPreference_becomeInvisible() {
149         doReturn(mPreferenceGroup).when(mPreferenceScreen).findPreference(anyString());
150 
151         mAvailableMediaDeviceGroupController.displayPreference(mPreferenceScreen);
152 
153         assertThat(mPreferenceGroup.isVisible()).isFalse();
154     }
155 
156     @Test
testRegister()157     public void testRegister() {
158         // register the callback in onStart()
159         mAvailableMediaDeviceGroupController.onStart();
160 
161         verify(mAvailableMediaBluetoothDeviceUpdater).registerCallback();
162         verify(mLocalBluetoothManager.getEventManager()).registerCallback(
163                 any(BluetoothCallback.class));
164         verify(mAvailableMediaBluetoothDeviceUpdater).refreshPreference();
165     }
166 
167     @Test
testUnregister()168     public void testUnregister() {
169         // unregister the callback in onStop()
170         mAvailableMediaDeviceGroupController.onStop();
171         verify(mAvailableMediaBluetoothDeviceUpdater).unregisterCallback();
172         verify(mLocalBluetoothManager.getEventManager()).unregisterCallback(
173                 any(BluetoothCallback.class));
174     }
175 
176     @Test
testGetAvailabilityStatus_noBluetoothFeature_returnUnSupported()177     public void testGetAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
178         doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
179 
180         assertThat(mAvailableMediaDeviceGroupController.getAvailabilityStatus()).isEqualTo(
181                 UNSUPPORTED_ON_DEVICE);
182     }
183 
184     @Test
testGetAvailabilityStatus_BluetoothFeature_returnSupported()185     public void testGetAvailabilityStatus_BluetoothFeature_returnSupported() {
186         doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
187 
188         assertThat(mAvailableMediaDeviceGroupController.getAvailabilityStatus()).isEqualTo(
189                 AVAILABLE_UNSEARCHABLE);
190     }
191 
192     @Test
setTitle_inCallState_showCallStateTitle()193     public void setTitle_inCallState_showCallStateTitle() {
194         mAudioManager.setMode(AudioManager.MODE_IN_CALL);
195         mAvailableMediaDeviceGroupController.onAudioModeChanged();
196 
197         assertThat(mPreferenceGroup.getTitle()).isEqualTo(
198                 mContext.getText(R.string.connected_device_call_device_title));
199     }
200 
201     @Test
setTitle_notInCallState_showMediaStateTitle()202     public void setTitle_notInCallState_showMediaStateTitle() {
203         mAudioManager.setMode(AudioManager.MODE_NORMAL);
204         mAvailableMediaDeviceGroupController.onAudioModeChanged();
205 
206         assertThat(mPreferenceGroup.getTitle()).isEqualTo(
207                 mContext.getText(R.string.connected_device_media_device_title));
208     }
209 
210     @Test
onStart_localBluetoothManagerNull_shouldNotCrash()211     public void onStart_localBluetoothManagerNull_shouldNotCrash() {
212         mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null;
213 
214         // Shouldn't crash
215         mAvailableMediaDeviceGroupController.onStart();
216     }
217 
218     @Test
onStop_localBluetoothManagerNull_shouldNotCrash()219     public void onStop_localBluetoothManagerNull_shouldNotCrash() {
220         mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null;
221 
222         // Shouldn't crash
223         mAvailableMediaDeviceGroupController.onStop();
224     }
225 }
226