• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE;
20 import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PAIR_AND_JOIN_SHARING;
21 
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.ArgumentMatchers.anyInt;
26 import static org.mockito.ArgumentMatchers.eq;
27 import static org.mockito.Mockito.doNothing;
28 import static org.mockito.Mockito.doReturn;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.never;
31 import static org.mockito.Mockito.spy;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.when;
34 import static org.robolectric.Shadows.shadowOf;
35 
36 import android.app.Activity;
37 import android.bluetooth.BluetoothAdapter;
38 import android.bluetooth.BluetoothDevice;
39 import android.bluetooth.BluetoothProfile;
40 import android.bluetooth.BluetoothStatusCodes;
41 import android.content.Context;
42 import android.content.Intent;
43 import android.content.res.Resources;
44 import android.graphics.drawable.Drawable;
45 import android.os.Bundle;
46 import android.os.Looper;
47 import android.platform.test.annotations.DisableFlags;
48 import android.platform.test.annotations.EnableFlags;
49 import android.platform.test.flag.junit.SetFlagsRule;
50 import android.util.Pair;
51 
52 import androidx.annotation.NonNull;
53 import androidx.annotation.Nullable;
54 import androidx.fragment.app.DialogFragment;
55 import androidx.fragment.app.FragmentActivity;
56 import androidx.fragment.app.FragmentManager;
57 import androidx.fragment.app.FragmentTransaction;
58 import androidx.lifecycle.Lifecycle;
59 import androidx.test.core.app.ApplicationProvider;
60 
61 import com.android.settings.R;
62 import com.android.settings.SettingsActivity;
63 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
64 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
65 import com.android.settings.testutils.shadow.ShadowFragment;
66 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
67 import com.android.settingslib.bluetooth.LocalBluetoothManager;
68 import com.android.settingslib.flags.Flags;
69 
70 import org.junit.Before;
71 import org.junit.Rule;
72 import org.junit.Test;
73 import org.junit.runner.RunWith;
74 import org.mockito.Answers;
75 import org.mockito.ArgumentCaptor;
76 import org.mockito.Mock;
77 import org.mockito.junit.MockitoJUnit;
78 import org.mockito.junit.MockitoRule;
79 import org.robolectric.Robolectric;
80 import org.robolectric.RobolectricTestRunner;
81 import org.robolectric.annotation.Config;
82 import org.robolectric.annotation.Implementation;
83 import org.robolectric.annotation.Implements;
84 import org.robolectric.annotation.RealObject;
85 import org.robolectric.annotation.Resetter;
86 import org.robolectric.shadow.api.Shadow;
87 
88 import java.util.HashMap;
89 import java.util.Map;
90 import java.util.concurrent.Executor;
91 
92 /** Tests for {@link BluetoothDevicePairingDetailBase}. */
93 @RunWith(RobolectricTestRunner.class)
94 @Config(shadows = {
95         ShadowBluetoothAdapter.class,
96         ShadowAlertDialogCompat.class,
97         ShadowFragment.class,
98 })
99 public class BluetoothDevicePairingDetailBaseTest {
100 
101     @Rule
102     public final MockitoRule mMockitoRule = MockitoJUnit.rule();
103     @Rule
104     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
105 
106     public static final String KEY_DEVICE_LIST_GROUP = "test_key";
107 
108     private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
109     private static final String TEST_DEVICE_ADDRESS_B = "00:B1:B1:B1:B1:B1";
110     private final Context mContext = ApplicationProvider.getApplicationContext();
111 
112     @Mock
113     private Resources mResource;
114     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
115     private LocalBluetoothManager mLocalManager;
116     @Mock
117     private CachedBluetoothDevice mCachedBluetoothDevice;
118     @Mock
119     private Drawable mDrawable;
120     private BluetoothAdapter mBluetoothAdapter;
121     private ShadowBluetoothAdapter mShadowBluetoothAdapter;
122     private BluetoothProgressCategory mAvailableDevicesCategory;
123     private BluetoothDevice mBluetoothDevice;
124     private TestBluetoothDevicePairingDetailBase mFragment;
125 
126     @Before
setUp()127     public void setUp() {
128         mAvailableDevicesCategory = spy(new BluetoothProgressCategory(mContext));
129         mBluetoothAdapter = spy(BluetoothAdapter.getDefaultAdapter());
130         mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
131         mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
132                 BluetoothStatusCodes.FEATURE_SUPPORTED);
133         mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
134                 BluetoothStatusCodes.FEATURE_SUPPORTED);
135         when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
136         final Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
137         when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs);
138         mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
139 
140         mFragment = spy(new TestBluetoothDevicePairingDetailBase());
141         when(mFragment.findPreference(KEY_DEVICE_LIST_GROUP)).thenReturn(mAvailableDevicesCategory);
142         doReturn(mContext).when(mFragment).getContext();
143         doReturn(mResource).when(mFragment).getResources();
144         mFragment.mDeviceListGroup = mAvailableDevicesCategory;
145         mFragment.mLocalManager = mLocalManager;
146         mFragment.mBluetoothAdapter = mBluetoothAdapter;
147         mFragment.initPreferencesFromPreferenceScreen();
148     }
149 
150     @Test
startScanning_startScanAndRemoveDevices()151     public void startScanning_startScanAndRemoveDevices() {
152         mFragment.enableScanning();
153 
154         verify(mFragment).startScanning();
155         verify(mAvailableDevicesCategory).removeAll();
156     }
157 
158     @Test
updateContent_stateOn()159     public void updateContent_stateOn() {
160         mFragment.updateContent(BluetoothAdapter.STATE_ON);
161 
162         assertThat(mBluetoothAdapter.isEnabled()).isTrue();
163         verify(mFragment).enableScanning();
164     }
165 
166     @Test
updateContent_stateOff_finish()167     public void updateContent_stateOff_finish() {
168         mFragment.updateContent(BluetoothAdapter.STATE_OFF);
169 
170         verify(mFragment).finish();
171     }
172 
173     @Test
updateBluetooth_bluetoothOff_turnOnBluetooth()174     public void updateBluetooth_bluetoothOff_turnOnBluetooth() {
175         mShadowBluetoothAdapter.setEnabled(false);
176 
177         mFragment.updateBluetooth();
178 
179         assertThat(mBluetoothAdapter.isEnabled()).isTrue();
180     }
181 
182     @Test
updateBluetooth_bluetoothOn_updateState()183     public void updateBluetooth_bluetoothOn_updateState() {
184         mShadowBluetoothAdapter.setEnabled(true);
185         doNothing().when(mFragment).updateContent(anyInt());
186 
187         mFragment.updateBluetooth();
188 
189         verify(mFragment).updateContent(anyInt());
190     }
191 
192     @Test
onBluetoothStateChanged_whenTurnedOnBTShowToast()193     public void onBluetoothStateChanged_whenTurnedOnBTShowToast() {
194         doNothing().when(mFragment).updateContent(anyInt());
195 
196         mFragment.onBluetoothStateChanged(BluetoothAdapter.STATE_ON);
197 
198         verify(mFragment).showBluetoothTurnedOnToast();
199     }
200 
201     @Test
202     @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
203     @DisableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
onDeviceBondStateChanged_bonded_notPairInSharing_finish()204     public void onDeviceBondStateChanged_bonded_notPairInSharing_finish() {
205         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
206         mFragment.mSelectedList.add(mBluetoothDevice);
207         setUpFragmentWithShareThenPairIntent(false);
208         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
209 
210         verify(mFragment).finish();
211     }
212 
213     @Test
214     @Config(shadows = ShadowDialogFragment.class)
215     @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
216     @DisableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
onDeviceBondStateChanged_bonded_shareThenPair_handle()217     public void onDeviceBondStateChanged_bonded_shareThenPair_handle() {
218         ShadowDialogFragment.reset();
219         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
220         mFragment.mSelectedList.add(mBluetoothDevice);
221         setUpFragmentWithShareThenPairIntent(true);
222         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
223         shadowOf(Looper.getMainLooper()).idle();
224 
225         ProgressDialogFragment progressDialog = mFragment.mProgressDialog;
226         assertThat(progressDialog).isNotNull();
227         assertThat(progressDialog.getMessage()).isEqualTo(
228                 mContext.getString(R.string.progress_dialog_connect_device_content,
229                         TEST_DEVICE_ADDRESS));
230         assertThat(
231                 ShadowDialogFragment.isIsShowing(ProgressDialogFragment.class.getName())).isTrue();
232         verify(mFragment, never()).finish();
233 
234         ShadowDialogFragment.reset();
235     }
236 
237     @Test
238     @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
239     @DisableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
onDeviceBondStateChanged_bonding_notPairInSharing_doNothing()240     public void onDeviceBondStateChanged_bonding_notPairInSharing_doNothing() {
241         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
242         mFragment.mSelectedList.add(mBluetoothDevice);
243         setUpFragmentWithShareThenPairIntent(false);
244         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
245 
246         verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(any(BluetoothDevice.class),
247                 any(Executor.class), any(BluetoothAdapter.OnMetadataChangedListener.class));
248     }
249 
250     @Test
251     @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
252     @DisableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
onDeviceBondStateChanged_bonding_shareThenPair_addListener()253     public void onDeviceBondStateChanged_bonding_shareThenPair_addListener() {
254         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
255         mFragment.mSelectedList.add(mBluetoothDevice);
256         setUpFragmentWithShareThenPairIntent(true);
257         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
258 
259         verify(mBluetoothAdapter).addOnMetadataChangedListener(eq(mBluetoothDevice),
260                 any(Executor.class),
261                 any(BluetoothAdapter.OnMetadataChangedListener.class));
262     }
263 
264     @Test
265     @DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
onDeviceBondStateChanged_unbonded_notPairInSharing_doNothing()266     public void onDeviceBondStateChanged_unbonded_notPairInSharing_doNothing() {
267         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
268         mFragment.mSelectedList.add(mBluetoothDevice);
269         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
270 
271         verify(mBluetoothAdapter, never()).removeOnMetadataChangedListener(
272                 any(BluetoothDevice.class), any(BluetoothAdapter.OnMetadataChangedListener.class));
273     }
274 
275     @Test
276     @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
277     @DisableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
onDeviceBondStateChanged_unbonded_shareThenPair_removeListener()278     public void onDeviceBondStateChanged_unbonded_shareThenPair_removeListener() {
279         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
280         mFragment.mSelectedList.add(mBluetoothDevice);
281         setUpFragmentWithShareThenPairIntent(true);
282         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
283         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
284 
285         verify(mBluetoothAdapter).removeOnMetadataChangedListener(eq(mBluetoothDevice),
286                 any(BluetoothAdapter.OnMetadataChangedListener.class));
287     }
288 
289     @Test
290     @DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
291     public void
onProfileConnectionStateChanged_deviceInSelectedListAndConnected_notInSharing_finish()292             onProfileConnectionStateChanged_deviceInSelectedListAndConnected_notInSharing_finish() {
293         final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
294         mFragment.mSelectedList.add(mBluetoothDevice);
295         mFragment.mSelectedList.add(device);
296 
297         when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
298         when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
299 
300         mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
301                 BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.A2DP);
302         shadowOf(Looper.getMainLooper()).idle();
303 
304         verify(mFragment).finish();
305     }
306 
307     @Test
308     @Config(shadows = ShadowDialogFragment.class)
309     @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
310     public void
onProfileConnectionStateChanged_inSelectedListAndConnected_shareThenPair_handle()311             onProfileConnectionStateChanged_inSelectedListAndConnected_shareThenPair_handle() {
312         ShadowDialogFragment.reset();
313         BluetoothDevice device = spy(mBluetoothDevice);
314         when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
315         mFragment.mSelectedList.add(device);
316         setUpFragmentWithShareThenPairIntent(true);
317         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
318         shadowOf(Looper.getMainLooper()).idle();
319 
320         when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
321         when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
322         when(mCachedBluetoothDevice.isConnectedLeAudioBroadcastAssistantDevice()).thenReturn(true);
323         when(mCachedBluetoothDevice.isConnectedVolumeControlDevice()).thenReturn(true);
324 
325         mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
326                 BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
327         shadowOf(Looper.getMainLooper()).idle();
328 
329         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
330         verify(mFragment.getActivity()).setResult(eq(Activity.RESULT_OK), captor.capture());
331         Intent intent = captor.getValue();
332         BluetoothDevice btDevice =
333                 intent != null
334                         ? intent.getParcelableExtra(EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE,
335                         BluetoothDevice.class)
336                         : null;
337         assertThat(btDevice).isNotNull();
338         assertThat(btDevice).isEqualTo(device);
339         verify(mFragment).finish();
340 
341         ShadowDialogFragment.reset();
342     }
343 
344     @Test
345     @DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
onProfileConnectionStateChanged_deviceNotInSelectedList_doNothing()346     public void onProfileConnectionStateChanged_deviceNotInSelectedList_doNothing() {
347         final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
348         mFragment.mSelectedList.add(device);
349 
350         when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
351         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
352 
353         mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
354                 BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.A2DP);
355 
356         // not crash
357     }
358 
359     @Test
360     @DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
onProfileConnectionStateChanged_deviceDisconnected_doNothing()361     public void onProfileConnectionStateChanged_deviceDisconnected_doNothing() {
362         final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
363         mFragment.mSelectedList.add(mBluetoothDevice);
364         mFragment.mSelectedList.add(device);
365 
366         when(mCachedBluetoothDevice.isConnected()).thenReturn(false);
367         when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
368 
369         mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
370                 BluetoothAdapter.STATE_DISCONNECTED, BluetoothProfile.A2DP);
371 
372         // not crash
373     }
374 
375     @Test
376     @DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
onProfileConnectionStateChanged_deviceInPreferenceMapAndConnected_removed()377     public void onProfileConnectionStateChanged_deviceInPreferenceMapAndConnected_removed() {
378         final BluetoothDevicePreference preference =
379                 new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
380                         true, BluetoothDevicePreference.SortType.TYPE_FIFO);
381         final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
382         mFragment.getDevicePreferenceMap().put(mCachedBluetoothDevice, preference);
383 
384         when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
385         when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
386 
387         mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
388                 BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.A2DP);
389 
390         assertThat(mFragment.getDevicePreferenceMap().size()).isEqualTo(0);
391     }
392 
393     @Test
394     @DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
onProfileConnectionStateChanged_deviceNotInPreferenceMap_doNothing()395     public void onProfileConnectionStateChanged_deviceNotInPreferenceMap_doNothing() {
396         final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
397         final BluetoothDevicePreference preference =
398                 new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
399                         true, BluetoothDevicePreference.SortType.TYPE_FIFO);
400         final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
401         final BluetoothDevice device2 = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
402         mFragment.getDevicePreferenceMap().put(mCachedBluetoothDevice, preference);
403 
404         when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
405         when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
406         when(cachedDevice.isConnected()).thenReturn(true);
407         when(cachedDevice.getDevice()).thenReturn(device2);
408         when(cachedDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS_B);
409         when(cachedDevice.getIdentityAddress()).thenReturn(TEST_DEVICE_ADDRESS_B);
410 
411         mFragment.onProfileConnectionStateChanged(cachedDevice, BluetoothAdapter.STATE_CONNECTED,
412                 BluetoothProfile.A2DP);
413 
414         // not crash
415     }
416 
setUpFragmentWithShareThenPairIntent(boolean enableShareThenPair)417     private void setUpFragmentWithShareThenPairIntent(boolean enableShareThenPair) {
418         Bundle args = new Bundle();
419         args.putBoolean(EXTRA_PAIR_AND_JOIN_SHARING, enableShareThenPair);
420         Intent intent = new Intent();
421         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
422         FragmentActivity activity = spy(Robolectric.setupActivity(FragmentActivity.class));
423         doReturn(intent).when(activity).getIntent();
424         doReturn(activity).when(mFragment).getActivity();
425         FragmentManager fragmentManager = mock(FragmentManager.class);
426         FragmentTransaction fragmentTransaction = mock(FragmentTransaction.class);
427         doReturn(fragmentTransaction).when(fragmentManager).beginTransaction();
428         doReturn(fragmentManager).when(mFragment).getFragmentManager();
429         doReturn(fragmentManager).when(mFragment).getChildFragmentManager();
430         Lifecycle lifecycle = mock(Lifecycle.class);
431         when(lifecycle.getCurrentState()).thenReturn(Lifecycle.State.RESUMED);
432         doReturn(lifecycle).when(mFragment).getLifecycle();
433         mFragment.mShouldTriggerShareThenPairFlow = mFragment.shouldTriggerShareThenPairFlow();
434     }
435 
436     private static class TestBluetoothDevicePairingDetailBase extends
437             BluetoothDevicePairingDetailBase {
438 
TestBluetoothDevicePairingDetailBase()439         TestBluetoothDevicePairingDetailBase() {
440             super();
441         }
442 
443         @Override
getMetricsCategory()444         public int getMetricsCategory() {
445             return 0;
446         }
447 
448         @Override
getDeviceListKey()449         public String getDeviceListKey() {
450             return KEY_DEVICE_LIST_GROUP;
451         }
452 
453         @Override
getPreferenceScreenResId()454         protected int getPreferenceScreenResId() {
455             return 0;
456         }
457 
458         @Override
getLogTag()459         protected String getLogTag() {
460             return "test_tag";
461         }
462     }
463 
464     /** Shadow of DialogFragment. */
465     @Implements(value = DialogFragment.class)
466     public static class ShadowDialogFragment {
467         @RealObject
468         private DialogFragment mDialogFragment;
469         private static Map<String, Boolean> sDialogStatus = new HashMap<>();
470 
471         /** Resetter of the shadow. */
472         @Resetter
reset()473         public static void reset() {
474             sDialogStatus.clear();
475         }
476 
477         /** Implementation for DialogFragment#show. */
478         @Implementation
show(@onNull FragmentManager manager, @Nullable String tag)479         public void show(@NonNull FragmentManager manager, @Nullable String tag) {
480             sDialogStatus.put(mDialogFragment.getClass().getName(), true);
481         }
482 
483         /** Implementation for DialogFragment#dismissAllowingStateLoss. */
484         @Implementation
dismissAllowingStateLoss()485         public void dismissAllowingStateLoss() {
486             sDialogStatus.put(mDialogFragment.getClass().getName(), false);
487         }
488 
489         /** Implementation for DialogFragment#dismiss. */
490         @Implementation
dismiss()491         public void dismiss() {
492             sDialogStatus.put(mDialogFragment.getClass().getName(), false);
493         }
494 
495         /** Check if DialogFragment is showing. */
isIsShowing(String clazzName)496         public static boolean isIsShowing(String clazzName) {
497             return sDialogStatus.getOrDefault(clazzName, false);
498         }
499     }
500 }
501