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 com.android.nfc.NfcDispatcher.DISPATCH_SUCCESS; 19 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.anyInt; 22 import static org.mockito.ArgumentMatchers.eq; 23 import static org.mockito.Mockito.mockingDetails; 24 import static org.mockito.Mockito.when; 25 26 import android.annotation.NonNull; 27 import android.annotation.Nullable; 28 import android.content.BroadcastReceiver; 29 import android.content.Context; 30 import android.content.ContextWrapper; 31 import android.content.Intent; 32 import android.content.IntentFilter; 33 import android.content.pm.ActivityInfo; 34 import android.content.pm.PackageManager; 35 import android.content.pm.PackageManager.ResolveInfoFlags; 36 import android.content.pm.ResolveInfo; 37 import android.content.res.Resources; 38 import android.nfc.Tag; 39 import android.os.Bundle; 40 import android.os.Handler; 41 import android.os.PowerManager; 42 import android.os.UserHandle; 43 import android.util.Log; 44 import androidx.test.core.content.pm.ApplicationInfoBuilder; 45 import androidx.test.ext.junit.runners.AndroidJUnit4; 46 import androidx.test.platform.app.InstrumentationRegistry; 47 48 import com.android.dx.mockito.inline.extended.ExtendedMockito; 49 import com.android.nfc.handover.HandoverDataParser; 50 51 import java.util.ArrayList; 52 import java.util.List; 53 import java.util.concurrent.atomic.AtomicReference; 54 55 import org.junit.After; 56 import org.junit.Assert; 57 import org.junit.Before; 58 import org.junit.Test; 59 import org.junit.runner.RunWith; 60 import org.mockito.Mockito; 61 import org.mockito.MockitoSession; 62 import org.mockito.quality.Strictness; 63 64 @RunWith(AndroidJUnit4.class) 65 public final class NfcReaderConflictOccurredTest { 66 67 private static final String TAG = NfcReaderConflictOccurredTest.class.getSimpleName(); 68 private boolean mNfcSupported; 69 70 private MockitoSession mStaticMockSession; 71 private NfcDispatcher mNfcDispatcher; 72 73 @Before setUp()74 public void setUp() { 75 mStaticMockSession = ExtendedMockito.mockitoSession() 76 .mockStatic(NfcStatsLog.class) 77 .strictness(Strictness.LENIENT) 78 .startMocking(); 79 80 Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 81 PackageManager mPackageManager = context.getPackageManager(); 82 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC_ANY)) { 83 mNfcSupported = false; 84 return; 85 } 86 mNfcSupported = true; 87 88 PackageManager mockPackageManager = Mockito.mock(PackageManager.class); 89 // multiple resolveInfos for Tag 90 when(mockPackageManager.queryIntentActivitiesAsUser( 91 any(Intent.class), 92 any(ResolveInfoFlags.class), 93 any(UserHandle.class))).thenReturn(constructConflictingResolveInfos()); 94 PowerManager mockPowerManager = Mockito.mock(PowerManager.class); 95 when(mockPowerManager.isInteractive()).thenReturn(false); 96 Resources mockResources = Mockito.mock(Resources.class); 97 when(mockResources.getBoolean(eq(R.bool.tag_intent_app_pref_supported))) 98 .thenReturn(false); 99 100 Context mockContext = new ContextWrapper(context) { 101 @Override 102 public PackageManager getPackageManager() { 103 Log.i(TAG, "[Mock] getPackageManager"); 104 return mockPackageManager; 105 } 106 107 @Override 108 public Object getSystemService(String name) { 109 if (Context.POWER_SERVICE.equals(name)) { 110 Log.i(TAG, "[Mock] mockPowerManager"); 111 return mockPowerManager; 112 } 113 return super.getSystemService(name); 114 } 115 116 @Override 117 public Resources getResources() { 118 Log.i(TAG, "[Mock] getResources"); 119 return mockResources; 120 } 121 @Override 122 public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver, 123 @NonNull IntentFilter filter, @Nullable String broadcastPermission, 124 @Nullable Handler scheduler) { 125 Log.i(TAG, "[Mock] getIntent"); 126 return Mockito.mock(Intent.class); 127 } 128 }; 129 130 InstrumentationRegistry.getInstrumentation().runOnMainSync( 131 () -> mNfcDispatcher = new NfcDispatcher( 132 mockContext, new HandoverDataParser(), false)); 133 Assert.assertNotNull(mNfcDispatcher); 134 } 135 136 @After tearDown()137 public void tearDown() { 138 mStaticMockSession.finishMocking(); 139 } 140 141 @Test testLogReaderConflict()142 public void testLogReaderConflict() { 143 if (!mNfcSupported) return; 144 145 Tag tag = Tag.createMockTag(null, new int[0], new Bundle[0], 0L); 146 int result = mNfcDispatcher.dispatchTag(tag); 147 ExtendedMockito.verify(() -> NfcStatsLog.write( 148 NfcStatsLog.NFC_READER_CONFLICT_OCCURRED)); 149 } 150 151 152 @Test testLogReaderSuccess()153 public void testLogReaderSuccess() { 154 if (!mNfcSupported) return; 155 156 Tag tag = Tag.createMockTag(null, new int[0], new Bundle[0], 0L); 157 int result = mNfcDispatcher.dispatchTag(tag); 158 Assert.assertEquals(result,DISPATCH_SUCCESS); 159 } 160 constructConflictingResolveInfos()161 public List<ResolveInfo> constructConflictingResolveInfos() { 162 List<ResolveInfo> mockResolves = new ArrayList<>(); 163 mockResolves.add(constructResolveInfo("appName1", "packageName1", 111)); 164 mockResolves.add(constructResolveInfo("appName2", "packageName2", 112)); 165 return mockResolves; 166 } 167 constructResolveInfo(String appName, String packageName, int uid)168 public ResolveInfo constructResolveInfo(String appName, String packageName, int uid) { 169 ResolveInfo resolveInfo = new ResolveInfo(); 170 resolveInfo.activityInfo = new ActivityInfo(); 171 resolveInfo.activityInfo.applicationInfo = 172 ApplicationInfoBuilder.newBuilder() 173 .setName(appName) 174 .setPackageName(packageName) 175 .build(); 176 resolveInfo.activityInfo.applicationInfo.uid = uid; 177 resolveInfo.activityInfo.exported = true; 178 return resolveInfo; 179 } 180 } 181