• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.nfc;
17 
18 import static android.nfc.tech.Ndef.EXTRA_NDEF_MSG;
19 
20 import static com.google.common.truth.Truth.assertThat;
21 
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.ArgumentMatchers.anyBoolean;
24 import static org.mockito.ArgumentMatchers.anyInt;
25 import static org.mockito.ArgumentMatchers.anyString;
26 import static org.mockito.ArgumentMatchers.eq;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.verify;
29 import static org.mockito.Mockito.when;
30 
31 import android.app.ActivityManager;
32 import android.app.KeyguardManager;
33 import android.app.PendingIntent;
34 import android.bluetooth.BluetoothProtoEnums;
35 import android.content.BroadcastReceiver;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.content.IntentFilter;
39 import android.content.pm.ActivityInfo;
40 import android.content.pm.ApplicationInfo;
41 import android.content.pm.PackageManager;
42 import android.content.pm.ResolveInfo;
43 import android.content.res.Resources;
44 import android.hardware.display.DisplayManager;
45 import android.nfc.INfcOemExtensionCallback;
46 import android.nfc.NdefMessage;
47 import android.nfc.NdefRecord;
48 import android.nfc.NfcAdapter;
49 import android.nfc.Tag;
50 import android.nfc.tech.Ndef;
51 import android.nfc.tech.NfcBarcode;
52 import android.nfc.tech.TagTechnology;
53 import android.os.Bundle;
54 import android.os.Handler;
55 import android.os.Message;
56 import android.os.PowerManager;
57 import android.os.RemoteException;
58 import android.os.UserHandle;
59 import android.os.UserManager;
60 import android.os.test.TestLooper;
61 
62 import androidx.test.ext.junit.runners.AndroidJUnit4;
63 
64 import com.android.dx.mockito.inline.extended.ExtendedMockito;
65 import com.android.nfc.flags.FeatureFlags;
66 import com.android.nfc.handover.HandoverDataParser;
67 import com.android.nfc.handover.PeripheralHandoverService;
68 
69 import org.junit.After;
70 import org.junit.Assert;
71 import org.junit.Before;
72 import org.junit.Test;
73 import org.junit.runner.RunWith;
74 import org.mockito.ArgumentCaptor;
75 import org.mockito.Mock;
76 import org.mockito.MockitoAnnotations;
77 import org.mockito.MockitoSession;
78 import org.mockito.quality.Strictness;
79 
80 import java.nio.charset.StandardCharsets;
81 import java.util.ArrayList;
82 import java.util.HashMap;
83 import java.util.List;
84 import java.util.Map;
85 import java.util.concurrent.atomic.AtomicBoolean;
86 
87 
88 @RunWith(AndroidJUnit4.class)
89 public final class NfcDispatcherTest {
90 
91     private static final String TAG = NfcDispatcherTest.class.getSimpleName();
92     @Mock private NfcInjector mNfcInjector;
93     private MockitoSession mStaticMockSession;
94     private NfcDispatcher mNfcDispatcher;
95     TestLooper mLooper;
96 
97     @Mock
98     private Context mockContext;
99     @Mock
100     private Resources mResources;
101     @Mock
102     private PackageManager mPackageManager;
103     @Mock
104     private PowerManager mPowerManager;
105     @Mock
106     KeyguardManager mKeyguardManager;
107     @Mock
108     DisplayManager mDisplayManager;
109     @Mock
110     UserManager mUserManager;
111     @Mock
112     ActivityManager mActivityManager;
113     @Mock
114     NfcAdapter mNfcAdapter;
115     @Mock
116     ForegroundUtils mForegroundUtils;
117     @Mock
118     AtomicBoolean mAtomicBoolean;
119     @Mock
120     DeviceConfigFacade mDeviceConfigFacade;
121 
122     @Before
setUp()123     public void setUp() throws PackageManager.NameNotFoundException {
124         mLooper = new TestLooper();
125         mStaticMockSession = ExtendedMockito.mockitoSession()
126                 .mockStatic(NfcStatsLog.class)
127                 .mockStatic(android.nfc.Flags.class)
128                 .mockStatic(com.android.nfc.flags.Flags.class)
129                 .mockStatic(NfcAdapter.class)
130                 .mockStatic(Ndef.class)
131                 .mockStatic(ForegroundUtils.class)
132                 .mockStatic(NfcWifiProtectedSetup.class)
133                 .strictness(Strictness.LENIENT)
134                 .startMocking();
135 
136         MockitoAnnotations.initMocks(this);
137 
138         when(mPowerManager.isInteractive()).thenReturn(false);
139         when(mockContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
140         when(mockContext.getSystemService(KeyguardManager.class)).thenReturn(mKeyguardManager);
141         when(mockContext.getSystemService(DisplayManager.class)).thenReturn(mDisplayManager);
142         when(mockContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
143         when(mockContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager);
144         when(ForegroundUtils.getInstance(mActivityManager)).thenReturn(mForegroundUtils);
145         when(mockContext.createPackageContextAsUser(anyString(), anyInt(), any()))
146                 .thenReturn(mockContext);
147         when(mockContext.createContextAsUser(any(), anyInt())).thenReturn(mockContext);
148         when(mockContext.getPackageManager()).thenReturn(mPackageManager);
149         when(mPackageManager.getApplicationLabel(any())).thenReturn("");
150         when(mockContext.getApplicationContext()).thenReturn(mockContext);
151         when(mResources.getBoolean(R.bool.tag_intent_app_pref_supported)).thenReturn(true);
152         when(mockContext.getResources()).thenReturn(mResources);
153         when(NfcAdapter.getDefaultAdapter(mockContext)).thenReturn(mNfcAdapter);
154         when(mNfcInjector.createAtomicBoolean()).thenReturn(mAtomicBoolean);
155 
156         mNfcDispatcher = new NfcDispatcher(mockContext,
157                 new HandoverDataParser(), mNfcInjector, true, mDeviceConfigFacade);
158         mLooper.dispatchAll();
159     }
160 
161     @After
tearDown()162     public void tearDown() {
163         mStaticMockSession.finishMocking();
164     }
165 
166     @Test
testLogOthers()167     public void testLogOthers() {
168         Tag tag = Tag.createMockTag(null, new int[0], new Bundle[0], 0L);
169         mNfcDispatcher.dispatchTag(tag);
170         ExtendedMockito.verify(() ->  NfcStatsLog.write(
171                 NfcStatsLog.NFC_TAG_OCCURRED,
172                 NfcStatsLog.NFC_TAG_OCCURRED__TYPE__PROVISION,
173                 -1,
174                 tag.getTechCodeList(),
175                 BluetoothProtoEnums.MAJOR_CLASS_UNCATEGORIZED,
176                 ""));
177     }
178 
179     @Test
testSetForegroundDispatchForWifiConnect()180     public void testSetForegroundDispatchForWifiConnect() {
181         PendingIntent pendingIntent = mock(PendingIntent.class);
182         mNfcDispatcher.setForegroundDispatch(pendingIntent, new IntentFilter[]{},
183                 new String[][]{});
184         Bundle bundle = mock(Bundle.class);
185         when(bundle.getParcelable(EXTRA_NDEF_MSG, android.nfc.NdefMessage.class)).thenReturn(
186                 mock(
187                         NdefMessage.class));
188         Tag tag = Tag.createMockTag(null, new int[]{1}, new Bundle[]{bundle}, 0L);
189         Ndef ndef = mock(Ndef.class);
190         when(Ndef.get(tag)).thenReturn(ndef);
191         NdefMessage ndefMessage = mock(NdefMessage.class);
192         when(ndef.getCachedNdefMessage()).thenReturn(ndefMessage);
193         NdefRecord ndefRecord = mock(NdefRecord.class);
194         NdefRecord[] records = {ndefRecord};
195         when(ndefMessage.getRecords()).thenReturn(records);
196         when(NfcWifiProtectedSetup.tryNfcWifiSetup(ndef, mockContext)).thenReturn(true);
197         mNfcDispatcher.dispatchTag(tag);
198         ExtendedMockito.verify(() -> NfcStatsLog.write(
199                 NfcStatsLog.NFC_TAG_OCCURRED,
200                 NfcStatsLog.NFC_TAG_OCCURRED__TYPE__WIFI_CONNECT,
201                 -1,
202                 tag.getTechCodeList(),
203                 BluetoothProtoEnums.MAJOR_CLASS_UNCATEGORIZED,
204                 ""));
205     }
206 
207     @Test
testPeripheralHandoverBTParing()208     public void testPeripheralHandoverBTParing() {
209         String btOobPayload = "00060E4C00520100000000000000000000000000000000000000000001";
210         Bundle bundle = mock(Bundle.class);
211         when(bundle.getParcelable(EXTRA_NDEF_MSG, android.nfc.NdefMessage.class)).thenReturn(
212                 mock(
213                         NdefMessage.class));
214         Tag tag = Tag.createMockTag(null, new int[]{1}, new Bundle[]{bundle}, 0L);
215         NdefMessage ndefMessage = mock(NdefMessage.class);
216         NdefRecord ndefRecord = mock(NdefRecord.class);
217         when(ndefRecord.getType()).thenReturn("application/vnd.bluetooth.ep.oob"
218                 .getBytes(StandardCharsets.US_ASCII));
219         when(ndefRecord.getTnf()).thenReturn(NdefRecord.TNF_MIME_MEDIA);
220         when(ndefRecord.getPayload()).thenReturn(btOobPayload.getBytes(StandardCharsets.US_ASCII));
221         NdefRecord[] records = {ndefRecord};
222         when(ndefMessage.getRecords()).thenReturn(records);
223         mNfcDispatcher.tryPeripheralHandover(ndefMessage, tag);
224         ExtendedMockito.verify(() -> NfcStatsLog.write(
225                 NfcStatsLog.NFC_TAG_OCCURRED,
226                 NfcStatsLog.NFC_TAG_OCCURRED__TYPE__BT_PAIRING,
227                 -1,
228                 tag.getTechCodeList(),
229                 BluetoothProtoEnums.MAJOR_CLASS_UNCATEGORIZED,
230                 ""));
231     }
232 
233     @Test
testCheckForAar()234     public void testCheckForAar() {
235         NdefRecord ndefRecord = mock(NdefRecord.class);
236         when(ndefRecord.getTnf()).thenReturn(NdefRecord.TNF_EXTERNAL_TYPE);
237         when(ndefRecord.getType()).thenReturn(NdefRecord.RTD_ANDROID_APP);
238         when(ndefRecord.getPayload()).thenReturn("test".getBytes(StandardCharsets.US_ASCII));
239         String result = NfcDispatcher.checkForAar(ndefRecord);
240         assertThat(result).isEqualTo("test");
241     }
242 
243     @Test
testCreateNfcResolverIntent()244     public void testCreateNfcResolverIntent() {
245         when(mResources.getBoolean(eq(R.bool.tag_intent_app_pref_supported))).thenReturn(true);
246         Tag tag = mock(Tag.class);
247         NdefMessage ndefMessage = mock(NdefMessage.class);
248         NdefRecord ndefRecord = NdefRecord.createUri("https://www.example.com");
249         when(ndefMessage.getRecords()).thenReturn(new NdefRecord[]{ndefRecord});
250         NfcDispatcher.DispatchInfo dispatchInfo = new NfcDispatcher
251                 .DispatchInfo(mockContext, tag, ndefMessage);
252         ResolveInfo activity = mock(ResolveInfo.class);
253         ActivityInfo activityInfo = mock(ActivityInfo.class);
254         activityInfo.packageName = "com.android.nfc";
255         activityInfo.name = "test";
256         ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
257         applicationInfo.uid = 0;
258         activityInfo.applicationInfo = applicationInfo;
259         activity.activityInfo = activityInfo;
260 
261         ResolveInfo activity2 = mock(ResolveInfo.class);
262         ActivityInfo activityInfo2 = mock(ActivityInfo.class);
263         activityInfo2.packageName = "com.android.nfc2";
264         activityInfo2.name = "test2";
265         ApplicationInfo applicationInfo2 = mock(ApplicationInfo.class);
266         applicationInfo2.uid = 1;
267         activityInfo2.applicationInfo = applicationInfo2;
268         activity2.activityInfo = activityInfo2;
269 
270         List<ResolveInfo> activities = new ArrayList<>();
271         activities.add(activity);
272         activities.add(activity2);
273         Map<String, Boolean> prefList = new HashMap<>();
274         prefList.put("com.android.nfc", false);
275         when(mNfcAdapter.getTagIntentAppPreferenceForUser(0)).thenReturn(prefList);
276         Assert.assertNotNull(dispatchInfo.intent);
277         dispatchInfo.intent.setAction(NfcAdapter.ACTION_TECH_DISCOVERED);
278         when(android.nfc.Flags.enableNfcMainline()).thenReturn(true);
279         when(com.android.nfc.flags.Flags.nfcAlertTagAppLaunch()).thenReturn(false);
280         dispatchInfo.checkPrefList(activities, 0);
281 
282         assertThat(dispatchInfo.rootIntent).isNotNull();
283         assertThat(dispatchInfo.rootIntent.getAction()).isNotNull();
284         assertThat(dispatchInfo.rootIntent.getAction())
285                 .isEqualTo(NfcAdapter.ACTION_SHOW_NFC_RESOLVER);
286     }
287 
288     @Test
testDecodeNfcBarcodeUri()289     public void testDecodeNfcBarcodeUri() {
290         PendingIntent pendingIntent = mock(PendingIntent.class);
291         IntentFilter[] intentFilters = {};
292         String[][] techLists = {{"Ndef"}};
293         mNfcDispatcher.setForegroundDispatch(pendingIntent, intentFilters, techLists);
294         ArgumentCaptor<Integer> callingUid = ArgumentCaptor.forClass(Integer.class);
295         verify(mForegroundUtils).registerUidToBackgroundCallback(any(), callingUid.capture());
296         Tag tag = mock(Tag.class);
297         Bundle bundle = new Bundle();
298         bundle.putInt(NfcBarcode.EXTRA_BARCODE_TYPE, NfcBarcode.TYPE_KOVIO);
299         when(tag.getTechExtras(TagTechnology.NFC_BARCODE)).thenReturn(bundle);
300         when(tag.hasTech(TagTechnology.NFC_BARCODE)).thenReturn(true);
301         when(tag.getId()).thenReturn(new byte[]{0x04, 0x01, 0x64, 0x0C});
302         when(tag.getTechList()).thenReturn(new String[]{"Ndef"});
303         mNfcDispatcher.dispatchTag(tag);
304         ExtendedMockito.verify(() -> NfcStatsLog.write(
305                 NfcStatsLog.NFC_TAG_OCCURRED,
306                 NfcStatsLog.NFC_TAG_OCCURRED__TYPE__FOREGROUND_DISPATCH,
307                 callingUid.getValue(),
308                 tag.getTechCodeList(),
309                 BluetoothProtoEnums.MAJOR_CLASS_UNCATEGORIZED,
310                 ""));
311     }
312 
313     @Test
testExtractAarPackages()314     public void testExtractAarPackages() {
315         NdefMessage ndefMessage = mock(NdefMessage.class);
316         NdefRecord ndefRecord = mock(NdefRecord.class);
317         when(ndefRecord.getTnf()).thenReturn(NdefRecord.TNF_EXTERNAL_TYPE);
318         when(ndefRecord.getType()).thenReturn(NdefRecord.RTD_ANDROID_APP);
319         when(ndefRecord.getPayload())
320                 .thenReturn("com.android.test".getBytes(StandardCharsets.US_ASCII));
321         when(ndefMessage.getRecords()).thenReturn(new NdefRecord[]{ndefRecord});
322         List<String> aarPackages = NfcDispatcher.extractAarPackages(ndefMessage);
323         assertThat(aarPackages).isNotNull();
324         assertThat(aarPackages.size()).isGreaterThan(0);
325         assertThat(aarPackages.get(0)).isEqualTo("com.android.test");
326     }
327 
328     @Test
testFinalize()329     public void testFinalize() throws Throwable {
330         mNfcDispatcher.finalize();
331         ArgumentCaptor<BroadcastReceiver> receiverArgumentCaptor = ArgumentCaptor.forClass(
332                 BroadcastReceiver.class);
333         verify(mockContext).unregisterReceiver(receiverArgumentCaptor.capture());
334         BroadcastReceiver broadcastReceiver = receiverArgumentCaptor.getValue();
335         assertThat(broadcastReceiver).isNotNull();
336     }
337 
338     @Test
testGetAppSearchIntent()339     public void testGetAppSearchIntent() {
340         Intent intent = NfcDispatcher.getAppSearchIntent("com.android.test");
341         assertThat(intent).isNotNull();
342         assertThat(intent.getAction()).isEqualTo(Intent.ACTION_VIEW);
343     }
344 
345     @Test
testGetOemAppSearchIntent()346     public void testGetOemAppSearchIntent() throws RemoteException {
347         INfcOemExtensionCallback nfcOemExtensionCallback = mock(INfcOemExtensionCallback.class);
348         mNfcDispatcher.setOemExtension(nfcOemExtensionCallback);
349         Intent intent = mNfcDispatcher.getOemAppSearchIntent("com.android.test");
350         ArgumentCaptor<NfcCallbackResultReceiver> argumentCaptor = ArgumentCaptor.forClass(
351                 NfcCallbackResultReceiver.class);
352         verify(nfcOemExtensionCallback).onGetOemAppSearchIntent(any(), argumentCaptor.capture());
353         NfcCallbackResultReceiver nfcCallbackResultReceiver = argumentCaptor.getValue();
354         assertThat(nfcCallbackResultReceiver).isNotNull();
355     }
356 
357     @Test
testIsComponentEnabled()358     public void testIsComponentEnabled() throws PackageManager.NameNotFoundException {
359         PackageManager packageManager = mock(PackageManager.class);
360         ResolveInfo resolveInfo = mock(ResolveInfo.class);
361         ActivityInfo activityInfo = mock(ActivityInfo.class);
362         activityInfo.packageName = "com.android.test";
363         activityInfo.name = "test";
364         resolveInfo.activityInfo = activityInfo;
365         when(packageManager.getActivityInfo(any(), anyInt())).thenReturn(activityInfo);
366         boolean result = NfcDispatcher.isComponentEnabled(packageManager, resolveInfo);
367         assertThat(result).isTrue();
368     }
369 
370     @Test
testQueryNfcIntentActivitiesAsUser()371     public void testQueryNfcIntentActivitiesAsUser() {
372         when(mResources.getBoolean(eq(R.bool.tag_intent_app_pref_supported)))
373                 .thenReturn(true);
374         Tag tag = mock(Tag.class);
375         NdefMessage ndefMessage = mock(NdefMessage.class);
376         NdefRecord ndefRecord = NdefRecord.createUri("https://www.example.com");
377         when(ndefMessage.getRecords()).thenReturn(new NdefRecord[]{ndefRecord});
378         NfcDispatcher.DispatchInfo dispatchInfo = new NfcDispatcher
379                 .DispatchInfo(mockContext, tag, ndefMessage);
380         UserHandle userHandle = mock(UserHandle.class);
381         List<UserHandle> luh = new ArrayList<>();
382         luh.add(userHandle);
383         when(mUserManager.getEnabledProfiles()).thenReturn(luh);
384         when(mUserManager.isQuietModeEnabled(userHandle)).thenReturn(true);
385         dispatchInfo.hasIntentReceiver();
386         verify(mPackageManager).queryIntentActivitiesAsUser(any(), any(), any());
387     }
388 
389     @Test
testReceiveOemCallbackResult()390     public void testReceiveOemCallbackResult() throws  RemoteException {
391         Tag tag = mock(Tag.class);
392         NdefMessage ndefMessage = mock(NdefMessage.class);
393         NdefRecord ndefRecord = NdefRecord.createUri("https://www.example.com");
394         when(ndefMessage.getRecords()).thenReturn(new NdefRecord[]{ndefRecord});
395         INfcOemExtensionCallback nfcOemExtensionCallback = mock(INfcOemExtensionCallback.class);
396         mNfcDispatcher.setOemExtension(nfcOemExtensionCallback);
397         mNfcDispatcher.receiveOemCallbackResult(tag, ndefMessage);
398         verify(nfcOemExtensionCallback).onNdefMessage(any(), any(), any());
399     }
400 
401     @Test
testTryNdef()402     public void testTryNdef() {
403         when(mResources.getBoolean(eq(R.bool.tag_intent_app_pref_supported)))
404                 .thenReturn(true);
405         Tag tag = mock(Tag.class);
406         NdefMessage ndefMessage = mock(NdefMessage.class);
407         NdefRecord ndefRecord = NdefRecord.createUri("https://www.example.com");
408         when(ndefMessage.getRecords()).thenReturn(new NdefRecord[]{ndefRecord});
409         UserHandle userHandle = mock(UserHandle.class);
410         List<UserHandle> luh = new ArrayList<>();
411         luh.add(userHandle);
412         when(mUserManager.getEnabledProfiles()).thenReturn(luh);
413         when(mUserManager.isQuietModeEnabled(userHandle)).thenReturn(false);
414         NfcDispatcher.DispatchInfo dispatchInfo = new NfcDispatcher
415                 .DispatchInfo(mockContext, tag, ndefMessage);
416         FeatureFlags featureFlags = mock(FeatureFlags.class);
417         when(featureFlags.sendViewIntentForUrlTagDispatch()).thenReturn(false);
418         when(mNfcInjector.getFeatureFlags()).thenReturn(featureFlags);
419         ResolveInfo ri = mock(ResolveInfo.class);
420         when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(ri);
421         mNfcDispatcher.tryNdef(dispatchInfo, ndefMessage);
422         verify(mPackageManager).resolveActivity(any(), anyInt());
423     }
424 
425     @Test
testGetUri()426     public void testGetUri() {
427         when(mResources.getBoolean(eq(R.bool.tag_intent_app_pref_supported)))
428                 .thenReturn(true);
429         Tag tag = mock(Tag.class);
430         NdefMessage ndefMessage = mock(NdefMessage.class);
431         NdefRecord ndefRecord = NdefRecord.createUri("https://www.example.com");
432         when(ndefMessage.getRecords()).thenReturn(new NdefRecord[]{ndefRecord});
433         NfcDispatcher.DispatchInfo dispatchInfo = new NfcDispatcher
434                 .DispatchInfo(mockContext, tag, ndefMessage);
435         String uri = dispatchInfo.getUri();
436         assertThat(uri).isNotNull();
437         assertThat(uri).isEqualTo("https://www.example.com");
438     }
439 
440     @Test
testIsWebIntent()441     public void testIsWebIntent() {
442         when(mResources.getBoolean(eq(R.bool.tag_intent_app_pref_supported)))
443                 .thenReturn(true);
444         Tag tag = mock(Tag.class);
445         NdefMessage ndefMessage = mock(NdefMessage.class);
446         NdefRecord ndefRecord = NdefRecord.createUri("https://www.example.com");
447         when(ndefMessage.getRecords()).thenReturn(new NdefRecord[]{ndefRecord});
448         NfcDispatcher.DispatchInfo dispatchInfo = new NfcDispatcher
449                 .DispatchInfo(mockContext, tag, ndefMessage);
450         boolean webIntent = dispatchInfo.isWebIntent();
451         assertThat(webIntent).isTrue();
452     }
453 
454     @Test
testSetViewIntent()455     public void testSetViewIntent() {
456         when(mResources.getBoolean(eq(R.bool.tag_intent_app_pref_supported)))
457                 .thenReturn(true);
458         Tag tag = mock(Tag.class);
459         NdefMessage ndefMessage = mock(NdefMessage.class);
460         NdefRecord ndefRecord = NdefRecord.createUri("https://www.example.com");
461         when(ndefMessage.getRecords()).thenReturn(new NdefRecord[]{ndefRecord});
462         NfcDispatcher.DispatchInfo dispatchInfo = new NfcDispatcher
463                 .DispatchInfo(mockContext, tag, ndefMessage);
464         Intent intent = dispatchInfo.setViewIntent();
465         assertThat(intent).isNotNull();
466         assertThat(intent.getAction()).isEqualTo(Intent.ACTION_VIEW);
467     }
468 
469     @Test
testTryStartActivity()470     public void testTryStartActivity() {
471         when(mResources.getBoolean(eq(R.bool.tag_intent_app_pref_supported)))
472                 .thenReturn(true);
473         Tag tag = mock(Tag.class);
474         NdefMessage ndefMessage = mock(NdefMessage.class);
475         NdefRecord ndefRecord = NdefRecord.createUri("https://www.example.com");
476         when(ndefMessage.getRecords()).thenReturn(new NdefRecord[]{ndefRecord});
477         NfcDispatcher.DispatchInfo dispatchInfo = new NfcDispatcher
478                 .DispatchInfo(mockContext, tag, ndefMessage);
479         ResolveInfo ri = mock(ResolveInfo.class);
480         ActivityInfo ai = mock(ActivityInfo.class);
481         ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
482         applicationInfo.uid = 0;
483         ai.applicationInfo = applicationInfo;
484         ai.packageName = "com.android.test";
485         ai.name = "test";
486         ai.exported = true;
487         ri.activityInfo = ai;
488         List<ResolveInfo> ris = new ArrayList<>();
489         ris.add(ri);
490         when(mPackageManager.queryIntentActivitiesAsUser(any(), any(), any())).thenReturn(ris);
491         boolean result = dispatchInfo.tryStartActivity();
492         assertThat(result).isTrue();
493         ExtendedMockito.verify(() -> NfcStatsLog.write(NfcStatsLog.NFC_TAG_OCCURRED,
494                 NfcStatsLog.NFC_TAG_OCCURRED__TYPE__APP_LAUNCH,
495                 0,
496                 tag.getTechCodeList(),
497                 BluetoothProtoEnums.MAJOR_CLASS_UNCATEGORIZED,
498                 ""));
499 
500     }
501 
502     @Test
testMessageHandler()503     public void testMessageHandler() {
504         Handler handler = mNfcDispatcher.getHandler();
505         Message msg = new Message();
506         msg.arg1 = 1;
507         msg.what = PeripheralHandoverService.MSG_HEADSET_NOT_CONNECTED;
508         handler.handleMessage(msg);
509         verify(mAtomicBoolean).set(true);
510     }
511 }
512