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