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.google.common.truth.Truth.assertThat;
19 
20 import static org.mockito.Mockito.doReturn;
21 import static org.mockito.Mockito.never;
22 import static org.mockito.Mockito.spy;
23 import static org.mockito.Mockito.verify;
24 import static org.mockito.Mockito.when;
25 
26 import android.bluetooth.BluetoothAdapter;
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.pm.PackageManager;
31 import android.text.BidiFormatter;
32 import android.text.TextUtils;
33 
34 import com.android.settings.R;
35 import com.android.settings.bluetooth.AlwaysDiscoverable;
36 import com.android.settings.core.BasePreferenceController;
37 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
38 import com.android.settingslib.widget.FooterPreference;
39 
40 import org.junit.Before;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 import org.mockito.Mock;
44 import org.mockito.MockitoAnnotations;
45 import org.robolectric.RobolectricTestRunner;
46 import org.robolectric.RuntimeEnvironment;
47 import org.robolectric.Shadows;
48 import org.robolectric.annotation.Config;
49 import org.robolectric.shadows.ShadowApplication;
50 import org.robolectric.util.ReflectionHelpers;
51 
52 import java.util.ArrayList;
53 import java.util.List;
54 
55 @RunWith(RobolectricTestRunner.class)
56 @Config(shadows = ShadowBluetoothAdapter.class)
57 public class DiscoverableFooterPreferenceControllerTest {
58 
59     private static final String DEVICE_NAME = "device name";
60 
61     @Mock
62     private PackageManager mPackageManager;
63     @Mock
64     private AlwaysDiscoverable mAlwaysDiscoverable;
65 
66     private Context mContext;
67     private FooterPreference mPreference;
68     private DiscoverableFooterPreferenceController mDiscoverableFooterPreferenceController;
69     private BroadcastReceiver mBluetoothChangedReceiver;
70     private ShadowApplication mShadowApplication;
71 
72     @Before
setUp()73     public void setUp() {
74         MockitoAnnotations.initMocks(this);
75         mShadowApplication = Shadows.shadowOf(RuntimeEnvironment.application);
76         mContext = spy(RuntimeEnvironment.application);
77 
78         doReturn(mPackageManager).when(mContext).getPackageManager();
79         mDiscoverableFooterPreferenceController =
80                 new DiscoverableFooterPreferenceController(mContext, "key");
81         mPreference = new FooterPreference(mContext);
82         ReflectionHelpers
83                 .setField(mDiscoverableFooterPreferenceController, "mPreference", mPreference);
84         ReflectionHelpers
85                 .setField(mDiscoverableFooterPreferenceController,
86                         "mAlwaysDiscoverable", mAlwaysDiscoverable);
87         mBluetoothChangedReceiver = mDiscoverableFooterPreferenceController
88                 .mBluetoothChangedReceiver;
89     }
90 
91     @Test
getAvailabilityStatus_noBluetoothFeature_returnUnSupported()92     public void getAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
93         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(false);
94 
95         assertThat(mDiscoverableFooterPreferenceController.getAvailabilityStatus()).isEqualTo(
96                 BasePreferenceController.UNSUPPORTED_ON_DEVICE);
97     }
98 
99     @Test
getAvailabilityStatus_BluetoothFeature_returnAvailableUnsearchable()100     public void getAvailabilityStatus_BluetoothFeature_returnAvailableUnsearchable() {
101         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(true);
102 
103         assertThat(mDiscoverableFooterPreferenceController.getAvailabilityStatus()).isEqualTo(
104                 BasePreferenceController.AVAILABLE_UNSEARCHABLE);
105     }
106 
107     @Test
onStart_setAlwaysDiscoverableAsTrue_shouldRegisterBluetoothChanged()108     public void onStart_setAlwaysDiscoverableAsTrue_shouldRegisterBluetoothChanged() {
109         mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(true);
110         mDiscoverableFooterPreferenceController.onStart();
111 
112         assertThat(getRegisteredBroadcastReceivers()).contains(mBluetoothChangedReceiver);
113         verify(mAlwaysDiscoverable).start();
114     }
115 
116     @Test
onStop_setAlwaysDiscoverableAsTrue_shouldUnregisterBluetoothChanged()117     public void onStop_setAlwaysDiscoverableAsTrue_shouldUnregisterBluetoothChanged() {
118         mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(true);
119         mDiscoverableFooterPreferenceController.onStart();
120         mDiscoverableFooterPreferenceController.onStop();
121 
122         assertThat(getRegisteredBroadcastReceivers()).doesNotContain(mBluetoothChangedReceiver);
123         verify(mAlwaysDiscoverable).stop();
124     }
125 
126     @Test
onStart_setAlwaysDiscoverableAsFalse_shouldNotRegisterBluetoothChanged()127     public void onStart_setAlwaysDiscoverableAsFalse_shouldNotRegisterBluetoothChanged() {
128         mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(false);
129         mDiscoverableFooterPreferenceController.onStart();
130 
131         assertThat(getRegisteredBroadcastReceivers()).contains(mBluetoothChangedReceiver);
132         verify(mAlwaysDiscoverable, never()).start();
133     }
134 
135     @Test
onStop_setAlwaysDiscoverableAsFalse_shouldNotUnregisterBluetoothChanged()136     public void onStop_setAlwaysDiscoverableAsFalse_shouldNotUnregisterBluetoothChanged() {
137         mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(false);
138         mDiscoverableFooterPreferenceController.onStart();
139         mDiscoverableFooterPreferenceController.onStop();
140 
141         assertThat(getRegisteredBroadcastReceivers()).doesNotContain(mBluetoothChangedReceiver);
142         verify(mAlwaysDiscoverable, never()).stop();
143     }
144 
145     @Test
onBluetoothStateChanged_bluetoothOn_updateTitle()146     public void onBluetoothStateChanged_bluetoothOn_updateTitle() {
147         BluetoothAdapter.getDefaultAdapter().setName(DEVICE_NAME);
148         sendBluetoothStateChangedIntent(BluetoothAdapter.STATE_ON);
149 
150         assertThat(mPreference.getTitle()).isEqualTo(generateTitle(DEVICE_NAME));
151     }
152 
153     @Test
onBluetoothStateChanged_bluetoothOff_updateTitle()154     public void onBluetoothStateChanged_bluetoothOff_updateTitle() {
155         BluetoothAdapter.getDefaultAdapter().setName(DEVICE_NAME);
156         sendBluetoothStateChangedIntent(BluetoothAdapter.STATE_OFF);
157 
158         assertThat(mPreference.getTitle()).isEqualTo(generateTitle(null));
159     }
160 
161     @Test
onStart_localBluetoothManagerNull_shouldNotCrash()162     public void onStart_localBluetoothManagerNull_shouldNotCrash() {
163         mDiscoverableFooterPreferenceController.mLocalManager = null;
164 
165         // Shouldn't crash
166         mDiscoverableFooterPreferenceController.onStart();
167     }
168 
169     @Test
onStop_localBluetoothManagerNull_shouldNotCrash()170     public void onStop_localBluetoothManagerNull_shouldNotCrash() {
171         mDiscoverableFooterPreferenceController.mLocalManager = null;
172 
173         // Shouldn't crash
174         mDiscoverableFooterPreferenceController.onStop();
175     }
176 
generateTitle(String deviceName)177     private CharSequence generateTitle(String deviceName) {
178         if (deviceName == null) {
179             return mContext.getString(R.string.bluetooth_off_footer);
180 
181         } else {
182             return TextUtils.expandTemplate(
183                     mContext.getText(R.string.bluetooth_device_name_summary),
184                     BidiFormatter.getInstance().unicodeWrap(deviceName));
185         }
186     }
187 
sendBluetoothStateChangedIntent(int state)188     private void sendBluetoothStateChangedIntent(int state) {
189         Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
190         intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
191         mBluetoothChangedReceiver.onReceive(mContext, intent);
192     }
193 
194     /**
195      * Return a list of all the registered broadcast receivers
196      */
getRegisteredBroadcastReceivers()197     private List<BroadcastReceiver> getRegisteredBroadcastReceivers() {
198         List<BroadcastReceiver> registeredBroadcastReceivers = new ArrayList<>();
199         List<ShadowApplication.Wrapper> registeredReceivers =
200                 mShadowApplication.getRegisteredReceivers();
201         for (ShadowApplication.Wrapper wrapper : registeredReceivers) {
202             registeredBroadcastReceivers.add(wrapper.getBroadcastReceiver());
203         }
204         return registeredBroadcastReceivers;
205     }
206 }