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 package com.android.nfc.utils;
18 
19 
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.pm.PackageManager;
25 import android.nfc.NfcAdapter;
26 import android.os.RemoteException;
27 import android.util.Log;
28 
29 import androidx.test.platform.app.InstrumentationRegistry;
30 import androidx.test.uiautomator.UiDevice;
31 
32 import com.google.android.mobly.snippet.Snippet;
33 import com.google.android.mobly.snippet.event.SnippetEvent;
34 import com.google.android.mobly.snippet.rpc.Rpc;
35 
36 import java.util.concurrent.CountDownLatch;
37 import java.util.concurrent.TimeUnit;
38 
39 public abstract class NfcSnippet implements Snippet {
40     protected static final String TAG = "NfcSnippet";
41     protected final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
42     private final UiDevice mDevice =
43             UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
44 
45     @Rpc(description = "Checks if NFC supported on device")
isNfcSupported()46     public boolean isNfcSupported() {
47         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC);
48     }
49 
50     @Rpc(description = "Checks if NFC HCE (host-card emulation) supported on device")
isNfcHceSupported()51     public boolean isNfcHceSupported() {
52         return mContext.getPackageManager()
53                 .hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
54     }
55 
56     /** Turns device screen off */
57     @Rpc(description = "Turns device screen off")
turnScreenOff()58     public void turnScreenOff() {
59         try {
60             mDevice.sleep();
61         } catch (RemoteException e) {
62             Log.e(TAG, "RemoteException", e);
63         }
64     }
65 
66     /** Turns device screen on */
67     @Rpc(description = "Turns device screen on")
turnScreenOn()68     public void turnScreenOn() {
69         try {
70             mDevice.wakeUp();
71         } catch (RemoteException e) {
72             Log.e(TAG, "RemoteException", e);
73         }
74     }
75 
76     /** Press device menu button to return device to home screen between tests. */
77     @Rpc(description = "Press menu button")
pressMenu()78     public void pressMenu() {
79         mDevice.pressMenu();
80     }
81 
82     @Rpc(description = "Log info level message to device logcat")
logInfo(String message)83     public void logInfo(String message) {
84         Log.i(TAG, message);
85     }
86 
87     /** Toggle NFC state */
88     @Rpc(description = "Blocking call to toggle NFC state")
setNfcState(boolean enable)89     public void setNfcState(boolean enable) throws InterruptedException {
90         NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(mContext);
91         int expectedState = enable ? NfcAdapter.STATE_ON : NfcAdapter.STATE_OFF;
92         if (nfcAdapter.getAdapterState() == expectedState) {
93             Log.i(TAG, "toggleNfc: Already in expected state: " + expectedState);
94             return;
95         }
96         CountDownLatch countDownLatch = new CountDownLatch(1);
97         IntentFilter intentFilter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
98         final BroadcastReceiver receiver = new BroadcastReceiver() {
99             @Override
100             public void onReceive(Context context, Intent intent) {
101                 if (NfcAdapter.ACTION_ADAPTER_STATE_CHANGED.equals(intent.getAction())) {
102                     int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
103                             NfcAdapter.STATE_OFF);
104                     if (expectedState == state) countDownLatch.countDown();
105                 }
106             }
107         };
108         mContext.registerReceiver(receiver, intentFilter);
109         if (enable) {
110             nfcAdapter.enable();
111         } else {
112             nfcAdapter.disable();
113         }
114         if (!countDownLatch.await(5, TimeUnit.SECONDS)) {
115             throw  new IllegalStateException("Waiting for NFC state change failed");
116         }
117     }
118 
119     /** Creates a SnippetBroadcastReceiver that listens for when the specified action is received */
registerSnippetBroadcastReceiver( String callbackId, String eventName, String action)120     protected void registerSnippetBroadcastReceiver(
121             String callbackId, String eventName, String action) {
122         IntentFilter filter = new IntentFilter(action);
123         mContext.registerReceiver(
124                 new SnippetBroadcastReceiver(
125                         mContext, new SnippetEvent(callbackId, eventName), action),
126                 filter,
127                 Context.RECEIVER_EXPORTED);
128     }
129 }
130