1 /* 2 * Copyright (C) 2024 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.nfc; 18 19 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.Mockito.mock; 22 import static org.mockito.Mockito.times; 23 import static org.mockito.Mockito.when; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.RequiresPermission; 28 import android.app.ActivityManager; 29 import android.content.BroadcastReceiver; 30 import android.content.ComponentName; 31 import android.content.ContentResolver; 32 import android.content.Context; 33 import android.content.ContextWrapper; 34 import android.content.Intent; 35 import android.content.IntentFilter; 36 import android.content.ServiceConnection; 37 import android.content.pm.PackageManager; 38 import android.nfc.Constants; 39 import android.nfc.cardemulation.HostNfcFService; 40 import android.nfc.cardemulation.NfcFServiceInfo; 41 import android.os.Build; 42 import android.os.Handler; 43 import android.os.IBinder; 44 import android.os.Message; 45 import android.os.Messenger; 46 import android.os.UserHandle; 47 import android.provider.Settings; 48 import android.util.Log; 49 50 import androidx.test.ext.junit.runners.AndroidJUnit4; 51 import androidx.test.platform.app.InstrumentationRegistry; 52 53 import com.android.dx.mockito.inline.extended.ExtendedMockito; 54 import com.android.nfc.cardemulation.AidRoutingManager; 55 import com.android.nfc.cardemulation.CardEmulationManager; 56 import com.android.nfc.cardemulation.HostNfcFEmulationManager; 57 import com.android.nfc.cardemulation.RegisteredAidCache; 58 import com.android.nfc.cardemulation.RegisteredT3tIdentifiersCache; 59 import com.android.nfc.cardemulation.RoutingOptionManager; 60 61 import org.junit.After; 62 import org.junit.Assert; 63 import org.junit.Before; 64 import org.junit.Test; 65 import org.junit.runner.RunWith; 66 import org.mockito.MockitoSession; 67 import org.mockito.quality.Strictness; 68 69 import com.android.nfc.flags.Flags; 70 71 @RunWith(AndroidJUnit4.class) 72 public class HostNfcFEmulationManagerTest { 73 74 private static final String TAG = HostNfcFEmulationManagerTest.class.getSimpleName(); 75 private boolean mNfcSupported; 76 private MockitoSession mStaticMockSession; 77 private HostNfcFEmulationManager mHostNfcFEmulationManager; 78 private ComponentName componentName; 79 80 @Before setUp()81 public void setUp() throws Exception { 82 mStaticMockSession = ExtendedMockito.mockitoSession() 83 .mockStatic(Flags.class) 84 .mockStatic(NfcStatsLog.class) 85 .mockStatic(Message.class) 86 .strictness(Strictness.LENIENT) 87 .startMocking(); 88 89 Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 90 PackageManager pm = context.getPackageManager(); 91 if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_ANY)) { 92 mNfcSupported = false; 93 return; 94 } 95 mNfcSupported = true; 96 97 Context mockContext = new ContextWrapper(context) { 98 99 public Context createContextAsUser(@NonNull UserHandle user, 100 @CreatePackageOptions int flags) { 101 if (Build.IS_ENG) { 102 throw new IllegalStateException("createContextAsUser not overridden!"); 103 } 104 return this; 105 } 106 107 public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver, 108 @NonNull IntentFilter filter, @Nullable String broadcastPermission, 109 @Nullable Handler scheduler) { 110 return mock(Intent.class); 111 } 112 113 public ContentResolver getContentResolver() { 114 return mock(ContentResolver.class); 115 } 116 117 public boolean bindServiceAsUser( 118 @NonNull @RequiresPermission Intent service, @NonNull ServiceConnection conn, 119 int flags, 120 @NonNull UserHandle user) { 121 return true; 122 } 123 124 public void unbindService(@NonNull ServiceConnection conn) { 125 126 } 127 128 129 }; 130 131 when(Flags.statsdCeEventsFlag()).thenReturn(false); 132 RegisteredT3tIdentifiersCache t3tIdentifiersCache = mock( 133 RegisteredT3tIdentifiersCache.class); 134 NfcFServiceInfo nfcFServiceInfo = mock(NfcFServiceInfo.class); 135 componentName = mock(ComponentName.class); 136 when(nfcFServiceInfo.getComponent()).thenReturn(componentName); 137 when(t3tIdentifiersCache.resolveNfcid2("6D2E616E64726F69")).thenReturn(nfcFServiceInfo); 138 Message message = mock(Message.class); 139 when(Message.obtain(null, HostNfcFService.MSG_COMMAND_PACKET)).thenReturn(message); 140 when(Message.obtain(null, HostNfcFService.MSG_DEACTIVATED)).thenReturn(message); 141 when(Message.obtain()).thenReturn(message); 142 143 InstrumentationRegistry.getInstrumentation().runOnMainSync( 144 () -> mHostNfcFEmulationManager = 145 new HostNfcFEmulationManager(mockContext, t3tIdentifiersCache)); 146 Assert.assertNotNull(mHostNfcFEmulationManager); 147 } 148 149 @After tearDown()150 public void tearDown() throws Exception { 151 mStaticMockSession.finishMocking(); 152 } 153 154 @Test testOnEnabledForegroundNfcFServiceChanged()155 public void testOnEnabledForegroundNfcFServiceChanged() { 156 if (!mNfcSupported) return; 157 158 String packageName = mHostNfcFEmulationManager.getEnabledFgServiceName(); 159 Assert.assertNull(packageName); 160 when(componentName.getPackageName()).thenReturn("com.android.nfc"); 161 mHostNfcFEmulationManager.onEnabledForegroundNfcFServiceChanged(0, componentName); 162 packageName = mHostNfcFEmulationManager.getEnabledFgServiceName(); 163 Assert.assertNotNull(packageName); 164 Assert.assertEquals("com.android.nfc", packageName); 165 166 } 167 168 @Test testOnHostEmulationData()169 public void testOnHostEmulationData() { 170 if (!mNfcSupported) return; 171 172 testOnEnabledForegroundNfcFServiceChanged(); 173 mHostNfcFEmulationManager.onHostEmulationData("com.android.nfc".getBytes()); 174 ExtendedMockito.verify(() -> NfcStatsLog.write(NfcStatsLog.NFC_CARDEMULATION_OCCURRED, 175 NfcStatsLog.NFC_CARDEMULATION_OCCURRED__CATEGORY__HCE_PAYMENT, 176 "HCEF", 177 0)); 178 } 179 180 @Test testOnNfcDisabled()181 public void testOnNfcDisabled() { 182 if (!mNfcSupported) return; 183 184 testOnHostEmulationData(); 185 ServiceConnection serviceConnection = mHostNfcFEmulationManager.getServiceConnection(); 186 Message message = mock(Message.class); 187 when(Message.obtain(null, HostNfcFService.MSG_COMMAND_PACKET)).thenReturn(message); 188 serviceConnection.onServiceConnected(mock(ComponentName.class), mock(IBinder.class)); 189 int userId = mHostNfcFEmulationManager.getServiceUserId(); 190 Assert.assertEquals(0, userId); 191 mHostNfcFEmulationManager.onNfcDisabled(); 192 userId = mHostNfcFEmulationManager.getServiceUserId(); 193 Assert.assertEquals(-1, userId); 194 ExtendedMockito.verify(() -> Message.obtain(null, HostNfcFService.MSG_COMMAND_PACKET)); 195 } 196 197 198 @Test testOnUserSwitched()199 public void testOnUserSwitched() { 200 if (!mNfcSupported) return; 201 202 testOnHostEmulationData(); 203 ServiceConnection serviceConnection = mHostNfcFEmulationManager.getServiceConnection(); 204 Message message = mock(Message.class); 205 when(Message.obtain(null, HostNfcFService.MSG_COMMAND_PACKET)).thenReturn(message); 206 serviceConnection.onServiceConnected(mock(ComponentName.class), mock(IBinder.class)); 207 int userId = mHostNfcFEmulationManager.getServiceUserId(); 208 Assert.assertEquals(0, userId); 209 mHostNfcFEmulationManager.onUserSwitched(); 210 boolean isUserSwitched = mHostNfcFEmulationManager.isUserSwitched(); 211 Assert.assertTrue(isUserSwitched); 212 userId = mHostNfcFEmulationManager.getServiceUserId(); 213 Assert.assertEquals(-1, userId); 214 ExtendedMockito.verify(() -> Message.obtain(null, HostNfcFService.MSG_COMMAND_PACKET)); 215 } 216 217 @Test testOnHostEmulationDeactivated()218 public void testOnHostEmulationDeactivated() { 219 if (!mNfcSupported) return; 220 221 testOnHostEmulationData(); 222 ServiceConnection serviceConnection = mHostNfcFEmulationManager.getServiceConnection(); 223 Message message = mock(Message.class); 224 when(Message.obtain(null, HostNfcFService.MSG_COMMAND_PACKET)).thenReturn(message); 225 serviceConnection.onServiceConnected(mock(ComponentName.class), mock(IBinder.class)); 226 ComponentName serviceName = mHostNfcFEmulationManager.getServiceName(); 227 Assert.assertNotNull(serviceName); 228 mHostNfcFEmulationManager.onHostEmulationDeactivated(); 229 serviceName = mHostNfcFEmulationManager.getServiceName(); 230 Assert.assertNull(serviceName); 231 } 232 } 233 234