• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.settings.bluetooth;
18 
19 import static android.bluetooth.BluetoothDevice.BOND_NONE;
20 
21 import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceSettingsController.KEY_HEARING_DEVICE_SETTINGS;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.Mockito.doReturn;
27 import static org.mockito.Mockito.eq;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.spy;
30 import static org.mockito.Mockito.times;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 
34 import android.app.settings.SettingsEnums;
35 import android.companion.CompanionDeviceManager;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.hardware.input.InputManager;
39 import android.os.Bundle;
40 import android.os.UserManager;
41 import android.platform.test.annotations.DisableFlags;
42 import android.platform.test.flag.junit.SetFlagsRule;
43 import android.util.FeatureFlagUtils;
44 import android.view.InputDevice;
45 import android.view.MenuInflater;
46 import android.view.MenuItem;
47 
48 import androidx.fragment.app.Fragment;
49 import androidx.fragment.app.FragmentActivity;
50 import androidx.fragment.app.FragmentManager;
51 import androidx.fragment.app.FragmentTransaction;
52 import androidx.preference.PreferenceScreen;
53 
54 import com.android.settings.R;
55 import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter;
56 import com.android.settings.flags.Flags;
57 import com.android.settings.testutils.FakeFeatureFactory;
58 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
59 import com.android.settingslib.bluetooth.LocalBluetoothManager;
60 import com.android.settingslib.core.AbstractPreferenceController;
61 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
62 
63 import com.google.common.collect.ImmutableList;
64 
65 import org.junit.Before;
66 import org.junit.Rule;
67 import org.junit.Test;
68 import org.junit.runner.RunWith;
69 import org.mockito.Answers;
70 import org.mockito.ArgumentCaptor;
71 import org.mockito.Mock;
72 import org.mockito.MockitoAnnotations;
73 import org.robolectric.Robolectric;
74 import org.robolectric.RobolectricTestRunner;
75 import org.robolectric.RuntimeEnvironment;
76 import org.robolectric.annotation.Config;
77 import org.robolectric.fakes.RoboMenu;
78 
79 import java.util.List;
80 
81 @RunWith(RobolectricTestRunner.class)
82 @Config(shadows = {
83         com.android.settings.testutils.shadow.ShadowUserManager.class,
84         com.android.settings.testutils.shadow.ShadowFragment.class,
85 })
86 public class BluetoothDeviceDetailsFragmentTest {
87     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
88 
89     private static final String TEST_ADDRESS = "55:66:77:88:99:AA";
90     private static final int TEST_DEVICE_ID = 123;
91 
92     private BluetoothDeviceDetailsFragment mFragment;
93     private Context mContext;
94     private RoboMenu mMenu;
95     private MenuInflater mInflater;
96     private FragmentTransaction mFragmentTransaction;
97     private FragmentActivity mActivity;
98 
99     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
100     private CachedBluetoothDevice mCachedDevice;
101     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
102     private LocalBluetoothManager mLocalManager;
103     @Mock
104     private PreferenceScreen mPreferenceScreen;
105     @Mock
106     private UserManager mUserManager;
107     @Mock
108     private InputManager mInputManager;
109     @Mock
110     private CompanionDeviceManager mCompanionDeviceManager;
111     @Mock
112     private DeviceDetailsFragmentFormatter mFormatter;
113 
114     @Before
setUp()115     public void setUp() {
116         MockitoAnnotations.initMocks(this);
117         mContext = spy(RuntimeEnvironment.application);
118         doReturn(mInputManager).when(mContext).getSystemService(InputManager.class);
119         doReturn(new int[]{TEST_DEVICE_ID}).when(mInputManager).getInputDeviceIds();
120         doReturn(TEST_ADDRESS).when(mInputManager).getInputDeviceBluetoothAddress(TEST_DEVICE_ID);
121 
122         doReturn(mCompanionDeviceManager).when(mContext)
123                 .getSystemService(CompanionDeviceManager.class);
124         when(mCompanionDeviceManager.getAllAssociations()).thenReturn(ImmutableList.of());
125         FakeFeatureFactory fakeFeatureFactory = FakeFeatureFactory.setupForTest();
126         when(fakeFeatureFactory.mBluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(any(),
127                 any(), any(), eq(mCachedDevice), any())).thenReturn(mFormatter);
128 
129         mFragment = setupFragment();
130         mFragment.onAttach(mContext);
131 
132         mMenu = new RoboMenu(mContext);
133         mInflater = new MenuInflater(mContext);
134     }
135 
136     @Test
verifyOnAttachResult()137     public void verifyOnAttachResult() {
138         assertThat(mFragment.mDeviceAddress).isEqualTo(TEST_ADDRESS);
139         assertThat(mFragment.mManager).isEqualTo(mLocalManager);
140         assertThat(mFragment.mCachedDevice).isEqualTo(mCachedDevice);
141         assertThat(mFragment.mInputDevice).isEqualTo(null);
142     }
143 
144     @Test
verifyOnAttachResult_flagEnabledAndInputDeviceSet_returnsInputDevice()145     public void verifyOnAttachResult_flagEnabledAndInputDeviceSet_returnsInputDevice() {
146         FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_SHOW_STYLUS_PREFERENCES,
147                 true);
148         InputDevice inputDevice = mock(InputDevice.class);
149         BluetoothDeviceDetailsFragment fragment = setupFragment();
150         FragmentActivity activity = mock(FragmentActivity.class);
151         doReturn(inputDevice).when(mInputManager).getInputDevice(TEST_DEVICE_ID);
152         doReturn(activity).when(fragment).getActivity();
153 
154         fragment.onAttach(mContext);
155 
156         assertThat(fragment.mDeviceAddress).isEqualTo(TEST_ADDRESS);
157         assertThat(fragment.mManager).isEqualTo(mLocalManager);
158         assertThat(fragment.mCachedDevice).isEqualTo(mCachedDevice);
159         assertThat(fragment.mInputDevice).isEqualTo(inputDevice);
160     }
161 
162     @Test
verifyOnAttachResult_flagDisabled_returnsNullInputDevice()163     public void verifyOnAttachResult_flagDisabled_returnsNullInputDevice() {
164         FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_SHOW_STYLUS_PREFERENCES,
165                 false);
166         InputDevice inputDevice = mock(InputDevice.class);
167         BluetoothDeviceDetailsFragment fragment = setupFragment();
168         FragmentActivity activity = mock(FragmentActivity.class);
169         doReturn(inputDevice).when(mInputManager).getInputDevice(TEST_DEVICE_ID);
170         doReturn(activity).when(fragment).getActivity();
171 
172         fragment.onAttach(mContext);
173 
174         assertThat(fragment.mDeviceAddress).isEqualTo(TEST_ADDRESS);
175         assertThat(fragment.mManager).isEqualTo(mLocalManager);
176         assertThat(fragment.mCachedDevice).isEqualTo(mCachedDevice);
177         assertThat(fragment.mInputDevice).isEqualTo(null);
178     }
179 
180     @Test
181     @DisableFlags(Flags.FLAG_ENABLE_BLUETOOTH_DEVICE_DETAILS_POLISH)
getTitle_displayEditTitle()182     public void getTitle_displayEditTitle() {
183         mFragment.onCreateOptionsMenu(mMenu, mInflater);
184 
185         final MenuItem item = mMenu.getItem(0);
186 
187         assertThat(item.getTitle()).isEqualTo(mContext.getString(R.string.bluetooth_rename_button));
188     }
189 
190     @Test
getTitle_inputDeviceTitle()191     public void getTitle_inputDeviceTitle() {
192         FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_SHOW_STYLUS_PREFERENCES,
193                 true);
194         InputDevice inputDevice = mock(InputDevice.class);
195         doReturn(true).when(inputDevice).supportsSource(InputDevice.SOURCE_STYLUS);
196         doReturn(inputDevice).when(mInputManager).getInputDevice(TEST_DEVICE_ID);
197         mFragment.onAttach(mContext);
198 
199         mFragment.setTitleForInputDevice();
200 
201         assertThat(mActivity.getTitle().toString()).isEqualTo(
202                 mContext.getString(R.string.stylus_device_details_title));
203     }
204 
205     @Test
getTitle_inputDeviceNull_doesNotSetTitle()206     public void getTitle_inputDeviceNull_doesNotSetTitle() {
207         FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_SHOW_STYLUS_PREFERENCES,
208                 true);
209         doReturn(null).when(mInputManager).getInputDevice(TEST_DEVICE_ID);
210         mFragment.onAttach(mContext);
211 
212         mFragment.setTitleForInputDevice();
213 
214         verify(mActivity, times(0)).setTitle(any());
215     }
216 
217     @Test
218     @DisableFlags(Flags.FLAG_ENABLE_BLUETOOTH_DEVICE_DETAILS_POLISH)
editMenu_clicked_showDialog()219     public void editMenu_clicked_showDialog() {
220         mFragment.onCreateOptionsMenu(mMenu, mInflater);
221         final MenuItem item = mMenu.getItem(0);
222         ArgumentCaptor<Fragment> captor = ArgumentCaptor.forClass(Fragment.class);
223 
224         mFragment.onOptionsItemSelected(item);
225 
226         assertThat(item.getItemId())
227                 .isEqualTo(BluetoothDeviceDetailsFragment.EDIT_DEVICE_NAME_ITEM_ID);
228         verify(mFragmentTransaction).add(captor.capture(), eq(RemoteDeviceNameDialogFragment.TAG));
229         RemoteDeviceNameDialogFragment dialog = (RemoteDeviceNameDialogFragment) captor.getValue();
230         assertThat(dialog).isNotNull();
231     }
232 
233     @Test
finishFragmentIfNecessary_deviceIsBondNone_finishFragment()234     public void finishFragmentIfNecessary_deviceIsBondNone_finishFragment() {
235         when(mCachedDevice.getBondState()).thenReturn(BOND_NONE);
236 
237         mFragment.finishFragmentIfNecessary();
238 
239         verify(mFragment).finish();
240     }
241 
242     @Test
createPreferenceControllers_launchFromHAPage_deviceControllerNotExist()243     public void createPreferenceControllers_launchFromHAPage_deviceControllerNotExist() {
244         BluetoothDeviceDetailsFragment fragment = setupFragment();
245         Intent intent = fragment.getActivity().getIntent();
246         intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
247                 SettingsEnums.ACCESSIBILITY_HEARING_AID_SETTINGS);
248         fragment.onAttach(mContext);
249 
250         List<AbstractPreferenceController> controllerList = fragment.createPreferenceControllers(
251                 mContext);
252 
253         assertThat(controllerList.stream()
254                 .anyMatch(controller -> controller.getPreferenceKey().equals(
255                         KEY_HEARING_DEVICE_SETTINGS))).isFalse();
256     }
257 
258     @Test
createPreferenceControllers_notLaunchFromHAPage_deviceControllerExist()259     public void createPreferenceControllers_notLaunchFromHAPage_deviceControllerExist() {
260         BluetoothDeviceDetailsFragment fragment = setupFragment();
261         Intent intent = fragment.getActivity().getIntent();
262         intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
263                 SettingsEnums.PAGE_UNKNOWN);
264         fragment.onAttach(mContext);
265 
266         List<AbstractPreferenceController> controllerList = fragment.createPreferenceControllers(
267                 mContext);
268 
269         assertThat(controllerList.stream()
270                 .anyMatch(controller -> controller.getPreferenceKey().equals(
271                         KEY_HEARING_DEVICE_SETTINGS))).isTrue();
272     }
273 
setupFragment()274     private BluetoothDeviceDetailsFragment setupFragment() {
275         BluetoothDeviceDetailsFragment fragment = spy(
276                 BluetoothDeviceDetailsFragment.newInstance(TEST_ADDRESS));
277         doReturn(mLocalManager).when(fragment).getLocalBluetoothManager(any());
278         doReturn(mCachedDevice).when(fragment).getCachedDevice(any());
279         doReturn(mPreferenceScreen).when(fragment).getPreferenceScreen();
280         doReturn(mUserManager).when(fragment).getUserManager();
281 
282         mActivity = spy(Robolectric.setupActivity(FragmentActivity.class));
283         doReturn(mActivity).when(fragment).getActivity();
284         doReturn(mContext).when(fragment).getContext();
285 
286         FragmentManager fragmentManager = mock(FragmentManager.class);
287         doReturn(fragmentManager).when(fragment).getFragmentManager();
288         mFragmentTransaction = mock(FragmentTransaction.class);
289         doReturn(mFragmentTransaction).when(fragmentManager).beginTransaction();
290 
291         doReturn(TEST_ADDRESS).when(mCachedDevice).getAddress();
292         doReturn(TEST_ADDRESS).when(mCachedDevice).getIdentityAddress();
293         Bundle args = new Bundle();
294         args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS, TEST_ADDRESS);
295         fragment.setArguments(args);
296 
297         return fragment;
298     }
299 }
300