1 2 /* 3 * Copyright (C) 2024 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.nfc; 19 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.Mockito.mock; 22 import static org.mockito.Mockito.when; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.content.BroadcastReceiver; 27 import android.content.ComponentName; 28 import android.content.Context; 29 import android.content.ContextWrapper; 30 import android.content.Intent; 31 import android.content.IntentFilter; 32 import android.content.pm.ApplicationInfo; 33 import android.content.pm.PackageManager; 34 import android.content.pm.ResolveInfo; 35 import android.content.pm.ServiceInfo; 36 import android.content.res.Resources; 37 import android.content.res.TypedArray; 38 import android.content.res.XmlResourceParser; 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.Looper; 44 import android.os.Message; 45 import android.os.UserHandle; 46 import android.os.test.TestLooper; 47 import android.util.AttributeSet; 48 import android.util.Log; 49 import android.util.Xml; 50 51 import androidx.test.ext.junit.runners.AndroidJUnit4; 52 import androidx.test.platform.app.InstrumentationRegistry; 53 54 import com.android.dx.mockito.inline.extended.ExtendedMockito; 55 import com.android.nfc.cardemulation.HostNfcFEmulationManager; 56 import com.android.nfc.cardemulation.RegisteredNfcFServicesCache; 57 58 import org.junit.After; 59 import org.junit.Assert; 60 import org.junit.Before; 61 import org.junit.Test; 62 import org.junit.runner.RunWith; 63 import org.mockito.MockitoSession; 64 import org.mockito.quality.Strictness; 65 import org.xmlpull.v1.XmlPullParser; 66 import org.xmlpull.v1.XmlPullParserException; 67 68 import java.io.IOException; 69 import java.util.ArrayList; 70 import java.util.List; 71 72 @RunWith(AndroidJUnit4.class) 73 public class RegisteredNfcFServicesCacheTest { 74 75 private static String TAG = RegisteredNfcFServicesCacheTest.class.getSimpleName(); 76 private boolean mNfcSupported; 77 private MockitoSession mStaticMockSession; 78 private RegisteredNfcFServicesCache mNfcFServicesCache; 79 private int mUserId = -1; 80 private RegisteredNfcFServicesCache.Callback mCallback; 81 82 @Before setUp()83 public void setUp() throws Exception { 84 85 mStaticMockSession = ExtendedMockito.mockitoSession() 86 .mockStatic(Xml.class) 87 .mockStatic(NfcStatsLog.class) 88 .strictness(Strictness.LENIENT) 89 .startMocking(); 90 91 Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 92 PackageManager pm = context.getPackageManager(); 93 if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_ANY)) { 94 mNfcSupported = false; 95 return; 96 } 97 mNfcSupported = true; 98 99 Context mockContext = new ContextWrapper(context) { 100 public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver, 101 @NonNull IntentFilter filter, @Nullable String broadcastPermission, 102 @Nullable Handler scheduler) { 103 return mock(Intent.class); 104 } 105 106 public Context createPackageContextAsUser( 107 @NonNull String packageName, @CreatePackageOptions int flags, 108 @NonNull UserHandle user) 109 throws PackageManager.NameNotFoundException { 110 Log.d(TAG, "createPackageContextAsUser called"); 111 return this; 112 } 113 114 public PackageManager getPackageManager() { 115 PackageManager packageManager = mock(PackageManager.class); 116 ResolveInfo resolveInfo = mock(ResolveInfo.class); 117 ServiceInfo serviceInfo = mock(ServiceInfo.class); 118 serviceInfo.name = "nfc"; 119 serviceInfo.packageName = "com.android.nfc"; 120 serviceInfo.permission = android.Manifest.permission.BIND_NFC_SERVICE; 121 ApplicationInfo applicationInfo = mock(ApplicationInfo.class); 122 serviceInfo.applicationInfo = applicationInfo; 123 Resources resources = mock(Resources.class); 124 125 try { 126 when(packageManager.getResourcesForApplication(applicationInfo)).thenReturn( 127 resources); 128 } catch (PackageManager.NameNotFoundException e) { 129 throw new RuntimeException(e); 130 } 131 XmlResourceParser parser = mock(XmlResourceParser.class); 132 AttributeSet attributeSet = mock(AttributeSet.class); 133 TypedArray typedArray = mock(TypedArray.class); 134 when(typedArray.getString( 135 com.android.internal.R.styleable.HostNfcFService_description)).thenReturn( 136 "nfc"); 137 when(resources.obtainAttributes(attributeSet, 138 com.android.internal.R.styleable.HostNfcFService)).thenReturn(typedArray); 139 when(Xml.asAttributeSet(parser)).thenReturn(attributeSet); 140 try { 141 when(parser.getEventType()).thenReturn(XmlPullParser.START_TAG, 142 XmlPullParser.END_TAG); 143 when(parser.next()).thenReturn(1, 0); 144 when(parser.getName()).thenReturn("host-nfcf-service"); 145 } catch (XmlPullParserException e) { 146 } catch (IOException e) { 147 throw new RuntimeException(e); 148 } 149 when(serviceInfo.loadXmlMetaData(packageManager, 150 HostNfcFService.SERVICE_META_DATA)).thenReturn(parser); 151 serviceInfo.loadXmlMetaData(packageManager, HostNfcFService.SERVICE_META_DATA); 152 resolveInfo.serviceInfo = serviceInfo; 153 List<ResolveInfo> list = new ArrayList<>(); 154 list.add(resolveInfo); 155 when(packageManager.queryIntentServicesAsUser(any(), 156 any(), 157 any())).thenReturn(list); 158 return packageManager; 159 } 160 161 }; 162 163 mCallback = mock(RegisteredNfcFServicesCache.Callback.class); 164 165 InstrumentationRegistry.getInstrumentation().runOnMainSync( 166 () -> mNfcFServicesCache = 167 new RegisteredNfcFServicesCache(mockContext, mCallback)); 168 Assert.assertNotNull(mNfcFServicesCache); 169 170 } 171 172 @After tearDown()173 public void tearDown() throws Exception { 174 mStaticMockSession.finishMocking(); 175 } 176 177 @Test testOnHostEmulationActivated()178 public void testOnHostEmulationActivated() { 179 if (!mNfcSupported) return; 180 181 boolean isActive = mNfcFServicesCache.isActivated(); 182 Assert.assertFalse(isActive); 183 mNfcFServicesCache.onHostEmulationActivated(); 184 isActive = mNfcFServicesCache.isActivated(); 185 Assert.assertTrue(isActive); 186 } 187 188 @Test testOnHostEmulationDeactivated()189 public void testOnHostEmulationDeactivated() { 190 if (!mNfcSupported) return; 191 192 mNfcFServicesCache.onHostEmulationActivated(); 193 boolean isActive = mNfcFServicesCache.isActivated(); 194 Assert.assertTrue(isActive); 195 mNfcFServicesCache.onHostEmulationDeactivated(); 196 isActive = mNfcFServicesCache.isActivated(); 197 Assert.assertFalse(isActive); 198 } 199 200 @Test testOnNfcDisabled()201 public void testOnNfcDisabled() { 202 if (!mNfcSupported) return; 203 204 mNfcFServicesCache.onHostEmulationActivated(); 205 boolean isActive = mNfcFServicesCache.isActivated(); 206 Assert.assertTrue(isActive); 207 mNfcFServicesCache.onNfcDisabled(); 208 isActive = mNfcFServicesCache.isActivated(); 209 Assert.assertFalse(isActive); 210 } 211 212 @Test testInvalidateCache()213 public void testInvalidateCache() { 214 if (!mNfcSupported) return; 215 216 Assert.assertEquals(-1, mUserId); 217 mNfcFServicesCache.invalidateCache(1); 218 List<NfcFServiceInfo> services = mNfcFServicesCache.getServices(1); 219 Assert.assertNotNull(services); 220 Assert.assertTrue(services.size() > 0); 221 ExtendedMockito.verify(mCallback).onNfcFServicesUpdated(1, services); 222 NfcFServiceInfo nfcFServiceInfo = services.get(0); 223 ComponentName cName = nfcFServiceInfo.getComponent(); 224 Assert.assertNotNull(cName); 225 Assert.assertEquals("com.android.nfc", cName.getPackageName()); 226 } 227 228 @Test testGetServices()229 public void testGetServices() { 230 if (!mNfcSupported) return; 231 232 mNfcFServicesCache.invalidateCache(1); 233 List<NfcFServiceInfo> services = mNfcFServicesCache.getServices(1); 234 Assert.assertNotNull(services); 235 Assert.assertTrue(services.size() > 0); 236 NfcFServiceInfo nfcFServiceInfo = services.get(0); 237 ComponentName cName = nfcFServiceInfo.getComponent(); 238 Assert.assertNotNull(cName); 239 Assert.assertEquals("com.android.nfc", cName.getPackageName()); 240 } 241 }