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 org.junit.Assert.assertNotNull;
21 import static org.mockito.ArgumentMatchers.eq;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.when;
24 
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.app.PendingIntent;
28 import android.bluetooth.BluetoothProtoEnums;
29 import android.content.BroadcastReceiver;
30 import android.content.Context;
31 import android.content.ContextWrapper;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.content.pm.PackageManager;
35 import android.content.res.Resources;
36 import android.nfc.NdefMessage;
37 import android.nfc.NdefRecord;
38 import android.nfc.Tag;
39 import android.nfc.tech.Ndef;
40 import android.os.Bundle;
41 import android.os.Handler;
42 import android.os.PowerManager;
43 import android.util.Log;
44 import androidx.test.ext.junit.runners.AndroidJUnit4;
45 import androidx.test.platform.app.InstrumentationRegistry;
46 
47 import com.android.dx.mockito.inline.extended.ExtendedMockito;
48 import com.android.nfc.handover.HandoverDataParser;
49 
50 import org.junit.After;
51 import org.junit.Assert;
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.mockito.Mockito;
56 import org.mockito.MockitoSession;
57 import org.mockito.quality.Strictness;
58 
59 import java.nio.charset.StandardCharsets;
60 
61 
62 @RunWith(AndroidJUnit4.class)
63 public final class NfcDispatcherTest {
64 
65     private static final String TAG = NfcDispatcherTest.class.getSimpleName();
66     private boolean mNfcSupported;
67 
68     private MockitoSession mStaticMockSession;
69     private NfcDispatcher mNfcDispatcher;
70 
71     private Context mockContext;
72 
73     @Before
setUp()74     public void setUp() {
75         mStaticMockSession = ExtendedMockito.mockitoSession()
76                 .mockStatic(NfcStatsLog.class)
77                 .mockStatic(Ndef.class)
78                 .mockStatic(NfcWifiProtectedSetup.class)
79                 .strictness(Strictness.LENIENT)
80                 .startMocking();
81 
82         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
83         PackageManager pm = context.getPackageManager();
84         if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_ANY)) {
85             mNfcSupported = false;
86             return;
87         }
88         mNfcSupported = true;
89 
90         PowerManager mockPowerManager = Mockito.mock(PowerManager.class);
91         when(mockPowerManager.isInteractive()).thenReturn(false);
92         Resources mockResources = Mockito.mock(Resources.class);
93         when(mockResources.getBoolean(eq(R.bool.tag_intent_app_pref_supported)))
94                 .thenReturn(false);
95 
96         mockContext = new ContextWrapper(context) {
97             @Override
98             public Object getSystemService(String name) {
99               if (Context.POWER_SERVICE.equals(name)) {
100                   Log.i(TAG, "[Mock] mockPowerManager");
101                   return mockPowerManager;
102               }
103               return super.getSystemService(name);
104             }
105 
106             @Override
107             public Resources getResources() {
108                 Log.i(TAG, "[Mock] getResources");
109                 return mockResources;
110             }
111             @Override
112             public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
113                     @NonNull IntentFilter filter, @Nullable String broadcastPermission,
114                     @Nullable Handler scheduler){
115                 Log.i(TAG, "[Mock] getIntent");
116                 return Mockito.mock(Intent.class);
117             }
118         };
119 
120         InstrumentationRegistry.getInstrumentation().runOnMainSync(
121               () -> mNfcDispatcher = new NfcDispatcher(mockContext,
122                       new HandoverDataParser(), false));
123         Assert.assertNotNull(mNfcDispatcher);
124     }
125 
126     @After
tearDown()127     public void tearDown() {
128         mStaticMockSession.finishMocking();
129     }
130 
131     @Test
testLogOthers()132     public void testLogOthers() {
133         if (!mNfcSupported) return;
134 
135         Tag tag = Tag.createMockTag(null, new int[0], new Bundle[0], 0L);
136         mNfcDispatcher.dispatchTag(tag);
137         ExtendedMockito.verify(() -> NfcStatsLog.write(
138                 NfcStatsLog.NFC_TAG_OCCURRED,
139                 NfcStatsLog.NFC_TAG_OCCURRED__TYPE__OTHERS,
140                 -1,
141                 tag.getTechCodeList(),
142                 BluetoothProtoEnums.MAJOR_CLASS_UNCATEGORIZED,
143                 ""));
144     }
145         @Test
testSetForegroundDispatchForWifiConnect()146         public void testSetForegroundDispatchForWifiConnect() {
147             if (!mNfcSupported) return;
148             PendingIntent pendingIntent = mock(PendingIntent.class);
149             mNfcDispatcher.setForegroundDispatch(pendingIntent, new IntentFilter[]{},
150                     new String[][]{});
151             Bundle bundle = mock(Bundle.class);
152             when(bundle.getParcelable(EXTRA_NDEF_MSG, android.nfc.NdefMessage.class)).thenReturn(
153                     mock(
154                             NdefMessage.class));
155             Tag tag = Tag.createMockTag(null, new int[]{1}, new Bundle[]{bundle}, 0L);
156             Ndef ndef = mock(Ndef.class);
157             when(Ndef.get(tag)).thenReturn(ndef);
158             NdefMessage ndefMessage = mock(NdefMessage.class);
159             when(ndef.getCachedNdefMessage()).thenReturn(ndefMessage);
160             NdefRecord ndefRecord = mock(NdefRecord.class);
161             NdefRecord[] records = {ndefRecord};
162             when(ndefMessage.getRecords()).thenReturn(records);
163             when(NfcWifiProtectedSetup.tryNfcWifiSetup(ndef, mockContext)).thenReturn(true);
164             mNfcDispatcher.dispatchTag(tag);
165             ExtendedMockito.verify(() -> NfcStatsLog.write(
166                     NfcStatsLog.NFC_TAG_OCCURRED,
167                     NfcStatsLog.NFC_TAG_OCCURRED__TYPE__WIFI_CONNECT,
168                     -1,
169                     tag.getTechCodeList(),
170                     BluetoothProtoEnums.MAJOR_CLASS_UNCATEGORIZED,
171                     ""));
172         }
173 
174     @Test
testPeripheralHandoverBTParing()175     public void testPeripheralHandoverBTParing() {
176         if (!mNfcSupported) return;
177 
178         String btOobPayload = "00060E4C00520100000000000000000000000000000000000000000001";
179         Bundle bundle = mock(Bundle.class);
180         when(bundle.getParcelable(EXTRA_NDEF_MSG, android.nfc.NdefMessage.class)).thenReturn(
181                 mock(
182                         NdefMessage.class));
183         Tag tag = Tag.createMockTag(null, new int[]{1}, new Bundle[]{bundle}, 0L);
184         NdefMessage ndefMessage = mock(NdefMessage.class);
185         NdefRecord ndefRecord = mock(NdefRecord.class);
186         when(ndefRecord.getType()).thenReturn("application/vnd.bluetooth.ep.oob"
187                 .getBytes(StandardCharsets.US_ASCII));
188         when(ndefRecord.getTnf()).thenReturn(NdefRecord.TNF_MIME_MEDIA);
189         when(ndefRecord.getPayload()).thenReturn(btOobPayload.getBytes(StandardCharsets.US_ASCII));
190         NdefRecord[] records = {ndefRecord};
191         when(ndefMessage.getRecords()).thenReturn(records);
192         mNfcDispatcher.tryPeripheralHandover(ndefMessage, tag);
193         ExtendedMockito.verify(() -> NfcStatsLog.write(
194                 NfcStatsLog.NFC_TAG_OCCURRED,
195                 NfcStatsLog.NFC_TAG_OCCURRED__TYPE__BT_PAIRING,
196                 -1,
197                 tag.getTechCodeList(),
198                 BluetoothProtoEnums.MAJOR_CLASS_UNCATEGORIZED,
199                 ""));
200     }
201 }
202