• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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 android.nfc.test;
18 
19 import static org.junit.Assume.assumeFalse;
20 
21 import android.app.Activity;
22 import android.app.ActivityManager;
23 import android.app.Instrumentation;
24 import android.app.KeyguardManager;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.pm.PackageManager;
29 import android.nfc.NfcAdapter;
30 import android.nfc.cardemulation.CardEmulation;
31 import android.nfc.cardemulation.PollingFrame;
32 import android.nfc.cardemulation.PollingFrame.PollingFrameType;
33 import android.os.Bundle;
34 import android.os.PowerManager;
35 import android.os.UserManager;
36 import android.util.Log;
37 import android.view.KeyEvent;
38 import androidx.test.core.app.ApplicationProvider;
39 import androidx.test.platform.app.InstrumentationRegistry;
40 import com.android.compatibility.common.util.CommonTestUtils;
41 import com.android.compatibility.common.util.SystemUtil;
42 import java.util.ArrayList;
43 import java.util.List;
44 import org.junit.Assert;
45 
46 public class TestUtils {
supportsHardware()47   static boolean supportsHardware() {
48     final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext()
49         .getPackageManager();
50     return pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
51   }
52 
createAndResumeActivity()53   static Activity createAndResumeActivity() {
54     return createAndResumeActivity(NfcFCardEmulationActivity.class);
55   }
56 
createAndResumeActivity(Class<? extends Activity> activityClass)57   static Activity createAndResumeActivity(Class<? extends Activity> activityClass) {
58     ensureUnlocked();
59     Context context = ApplicationProvider.getApplicationContext();
60     Intent intent = new Intent(context, activityClass);
61     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
62     Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
63     InstrumentationRegistry.getInstrumentation().callActivityOnResume(activity);
64     ComponentName topComponentName = context.getSystemService(ActivityManager.class)
65         .getRunningTasks(1).get(0).topActivity;
66     Assert.assertEquals("Foreground activity not in the foreground",
67         activityClass.getName(), topComponentName.getClassName());
68     return activity;
69   }
70 
ensurePreferredService(Class serviceClass, Context context)71   static void ensurePreferredService(Class serviceClass, Context context) {
72     NfcAdapter adapter = NfcAdapter.getDefaultAdapter(context);
73     final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
74     int resId =
75         serviceClass == CustomHostApduService.class
76             ? android.nfc.test.R.string.CustomPaymentService
77             : -1;
78     final String desc = context.getResources().getString(resId);
79     ensurePreferredService(desc, context);
80   }
81 
ensureUnlocked()82   static void ensureUnlocked() {
83     final Context context = InstrumentationRegistry.getInstrumentation().getContext();
84     final UserManager userManager = context.getSystemService(UserManager.class);
85     assumeFalse(userManager.isHeadlessSystemUserMode());
86     final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
87     final PowerManager pm = context.getSystemService(PowerManager.class);
88     final KeyguardManager km = context.getSystemService(KeyguardManager.class);
89     try {
90       if (pm != null && !pm.isInteractive()) {
91         SystemUtil.runShellCommand("input keyevent KEYCODE_WAKEUP");
92         CommonTestUtils.waitUntil(
93             "Device does not wake up after 5 seconds", 5, () -> pm != null && pm.isInteractive());
94       }
95       if (km != null && km.isKeyguardLocked()) {
96         CommonTestUtils.waitUntil(
97             "Device does not unlock after 30 seconds",
98             30,
99             () -> {
100               SystemUtil.runWithShellPermissionIdentity(
101                   () -> instrumentation.sendKeyDownUpSync((KeyEvent.KEYCODE_MENU)));
102               return km != null && !km.isKeyguardLocked();
103             });
104       }
105     } catch (InterruptedException|AssertionError e) {
106     }
107   }
108 
ensurePreferredService(String serviceDesc, Context context)109   static void ensurePreferredService(String serviceDesc, Context context) {
110     NfcAdapter adapter = NfcAdapter.getDefaultAdapter(context);
111     final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
112     try {
113       CommonTestUtils.waitUntil(
114           "Default service hasn't updated",
115           6,
116           () -> serviceDesc.equals(cardEmulation.getDescriptionForPreferredPaymentService()));
117     } catch (InterruptedException|AssertionError e) {
118     }
119   }
120 
121   static PollLoopReceiver sCurrentPollLoopReceiver = null;
122 
123   static class PollLoopReceiver {
124     int mFrameIndex = 0;
125     ArrayList<PollingFrame> mFrames;
126     String mServiceName;
127     ArrayList<PollingFrame> mReceivedFrames;
128     String mReceivedServiceName;
129     ArrayList<String> mReceivedServiceNames;
130 
PollLoopReceiver(ArrayList<PollingFrame> frames, String serviceName)131     PollLoopReceiver(ArrayList<PollingFrame> frames, String serviceName) {
132       mFrames = frames;
133       mServiceName = serviceName;
134       mReceivedFrames = new ArrayList<PollingFrame>();
135       mReceivedServiceNames = new ArrayList<String>();
136     }
137 
notifyPollingLoop(String className, List<PollingFrame> receivedFrames)138     void notifyPollingLoop(String className, List<PollingFrame> receivedFrames) {
139       if (receivedFrames == null) {
140         return;
141       }
142       mReceivedFrames.addAll(receivedFrames);
143       mReceivedServiceName = className;
144       mReceivedServiceNames.add(className);
145       if (mReceivedFrames.size() < mFrames.size()) {
146         return;
147       }
148       synchronized (this) {
149         this.notify();
150       }
151     }
152 
test()153     void test() {
154       if (mReceivedFrames.size() > mFrames.size()) {
155         Assert.fail("received more frames than sent");
156       } else if (mReceivedFrames.size() < mFrames.size()) {
157         Assert.fail("received fewer frames than sent");
158       }
159       for (PollingFrame receivedFrame : mReceivedFrames) {
160         Assert.assertEquals(mFrames.get(mFrameIndex).getType(), receivedFrame.getType());
161         Assert.assertEquals(
162             mFrames.get(mFrameIndex).getVendorSpecificGain(),
163             receivedFrame.getVendorSpecificGain());
164         Assert.assertEquals(mFrames.get(mFrameIndex).getTimestamp(), receivedFrame.getTimestamp());
165         Assert.assertArrayEquals(mFrames.get(mFrameIndex).getData(), receivedFrame.getData());
166         mFrameIndex++;
167       }
168       if (mServiceName != null) {
169         Assert.assertEquals(mServiceName, mReceivedServiceName);
170       }
171     }
172   }
173 
notifyPollingLoopAndWait( ArrayList<PollingFrame> frames, String serviceName, Context context)174   static List<PollingFrame> notifyPollingLoopAndWait(
175       ArrayList<PollingFrame> frames, String serviceName, Context context) {
176     NfcAdapter adapter = NfcAdapter.getDefaultAdapter(context);
177     sCurrentPollLoopReceiver = new PollLoopReceiver(frames, serviceName);
178     for (PollingFrame frame : frames) {
179       adapter.notifyPollingLoop(frame);
180     }
181     synchronized (sCurrentPollLoopReceiver) {
182       try {
183         sCurrentPollLoopReceiver.wait(5000);
184       } catch (InterruptedException ie) {
185         Assert.assertNull(ie);
186       }
187     }
188     sCurrentPollLoopReceiver.test();
189     Assert.assertEquals(frames.size(), sCurrentPollLoopReceiver.mFrameIndex);
190     List<PollingFrame> receivedFrames = sCurrentPollLoopReceiver.mReceivedFrames;
191     sCurrentPollLoopReceiver = null;
192     return receivedFrames;
193   }
194 
createFrame(@ollingFrameType int type)195   static PollingFrame createFrame(@PollingFrameType int type) {
196     if (type == PollingFrame.POLLING_LOOP_TYPE_ON || type == PollingFrame.POLLING_LOOP_TYPE_OFF) {
197       return new PollingFrame(
198           type,
199           new byte[] {((type == PollingFrame.POLLING_LOOP_TYPE_ON) ? (byte) 0x01 : (byte) 0x00)},
200           8,
201           0,
202           false);
203     }
204     return new PollingFrame(type, null, 8, 0, false);
205   }
206 
createFrameWithData(@ollingFrameType int type, byte[] data)207   static PollingFrame createFrameWithData(@PollingFrameType int type, byte[] data) {
208     return new PollingFrame(type, data, 8, (long) Integer.MAX_VALUE + 1L, false);
209   }
210 
211   public abstract static class CommandApduProcessor {
processCommandApdu(String serviceName, byte[] apdu, Bundle extras)212     public abstract byte[] processCommandApdu(String serviceName, byte[] apdu, Bundle extras);
213   }
214 
215   static CommandApduProcessor sCurrentCommandApduProcessor = null;
216 
killNfcService()217   public static void killNfcService() {
218     Log.w(TAG, "Attempting to kill the NFC service...");
219 
220     SystemUtil.runShellCommand("killall com.android.nfc");
221   }
222 
223   private static final String TAG = "TestUtils";
224 }
225