• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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.cardemulation;
18 
19 import static android.nfc.cardemulation.HostApduService.MSG_RESPONSE_APDU;
20 import static android.nfc.cardemulation.HostApduService.MSG_UNHANDLED;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.mockito.Mockito.CALLS_REAL_METHODS;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.never;
26 import static org.mockito.Mockito.only;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.content.Intent;
31 import android.nfc.Flags;
32 import android.os.Bundle;
33 import android.os.Looper;
34 import android.os.Message;
35 import android.os.Messenger;
36 import android.os.RemoteException;
37 
38 import com.android.dx.mockito.inline.extended.ExtendedMockito;
39 
40 import org.junit.After;
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.mockito.MockitoAnnotations;
44 import org.mockito.MockitoSession;
45 import org.mockito.quality.Strictness;
46 
47 public class HostApduServiceTest {
48     private byte[] sampleApdu = "EO00001800".getBytes();
49     private HostApduService.MsgHandler mHandler;
50     private SampleHostApduService mSampleService;
51     private MockitoSession mMockitoSession;
52 
53     class SampleHostApduService extends HostApduService {
54 
55         @Override
processCommandApdu(byte[] commandApdu, Bundle extras)56         public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
57             return new byte[0];
58         }
59 
60         @Override
onDeactivated(int reason)61         public void onDeactivated(int reason) {
62 
63         }
64     }
65 
66     @Before
setUp()67     public void setUp() {
68         mMockitoSession = ExtendedMockito.mockitoSession()
69                 .mockStatic(Flags.class)
70                 .mockStatic(com.android.nfc.module.flags.Flags.class)
71                 .strictness(Strictness.LENIENT)
72                 .startMocking();
73         MockitoAnnotations.initMocks(this);
74         if (Looper.myLooper() == null) {
75             Looper.prepare();
76         }
77         mSampleService = mock(SampleHostApduService.class, CALLS_REAL_METHODS);
78         mHandler = mSampleService.getMsgHandler();
79     }
80 
81     @After
tearDown()82     public void tearDown() {
83         mMockitoSession.finishMocking();
84     }
85 
86     @Test
testHandleMessageWithCmdApdu()87     public void testHandleMessageWithCmdApdu() {
88         Bundle bundle = mock(Bundle.class);
89         Message msg = mock(Message.class);
90         Messenger mNfcService = mock(Messenger.class);
91         msg.what = HostApduService.MSG_COMMAND_APDU;
92         msg.replyTo = mNfcService;
93         when(msg.getData()).thenReturn(bundle);
94         when(bundle.getByteArray(HostApduService.KEY_DATA)).thenReturn(sampleApdu);
95 
96         mHandler.post(() -> {
97             mHandler.handleMessage(msg);
98             verify(msg).getData();
99         });
100     }
101 
102     @Test
testHandleMessageWithResponseApduWhenServiceDeactivated()103     public void testHandleMessageWithResponseApduWhenServiceDeactivated() {
104         Message msg = mock(Message.class);
105         msg.what = MSG_RESPONSE_APDU;
106 
107         when(mSampleService.getNfcService()).thenReturn(null);
108         mHandler.post(() -> {
109             mHandler.handleMessage(msg);
110             verify(mSampleService).getNfcService();
111         });
112     }
113 
114     @Test
testHandleMessageWithResponseApdu()115     public void testHandleMessageWithResponseApdu() {
116         Message msg = mock(Message.class);
117         Messenger mNfcService = mock(Messenger.class);
118         msg.what = MSG_RESPONSE_APDU;
119         msg.replyTo = mNfcService;
120 
121         when(mSampleService.getNfcService()).thenReturn(mNfcService);
122         mHandler.post(() -> {
123             mHandler.handleMessage(msg);
124             verify(mSampleService).getMessenger();
125             try {
126                 verify(mNfcService).send(msg);
127             } catch (RemoteException e) {
128                 throw new RuntimeException(e);
129             }
130         });
131     }
132 
133     @Test
testHandleMessageWithApduAck()134     public void testHandleMessageWithApduAck() {
135         Message msg = mock(Message.class);
136         msg.what = HostApduService.MSG_RESPONSE_APDU_ACK;
137 
138         mHandler.post(() -> {
139             mHandler.handleMessage(msg);
140             verify(mSampleService, never()).getNfcService();
141         });
142     }
143 
144     @Test
testHandleMessageWithMsgDeactivated()145     public void testHandleMessageWithMsgDeactivated() {
146         Message msg = Message.obtain();
147         msg.what = HostApduService.MSG_DEACTIVATED;
148         msg.arg1 = 1;
149 
150         mHandler.post(() -> {
151             mHandler.handleMessage(msg);
152             verify(mSampleService).setNfcService(null);
153             verify(mSampleService).onDeactivated(1);
154         });
155     }
156 
157     @Test
testHandleMessageWithMsgUnhandledWhenServiceDeactivated()158     public void testHandleMessageWithMsgUnhandledWhenServiceDeactivated() {
159         Message msg = mock(Message.class);
160         msg.what = MSG_UNHANDLED;
161         when(mSampleService.getNfcService()).thenReturn(null);
162 
163         mHandler.post(() -> {
164             mHandler.handleMessage(msg);
165             verify(mSampleService, only()).getNfcService();
166         });
167     }
168 
169     @Test
testHandleMessageWithMsgUnhandled()170     public void testHandleMessageWithMsgUnhandled() {
171         Message msg = mock(Message.class);
172         msg.what = MSG_UNHANDLED;
173         Messenger mNfcService = mock(Messenger.class);
174         when(mSampleService.getNfcService()).thenReturn(mNfcService);
175 
176         mHandler.post(() -> {
177             mHandler.handleMessage(msg);
178             verify(mSampleService).getMessenger();
179         });
180     }
181 
182     @Test
testHandleMessageWithPollingLoop()183     public void testHandleMessageWithPollingLoop() {
184         Message msg = mock(Message.class);
185         msg.what = HostApduService.MSG_POLLING_LOOP;
186         when(com.android.nfc.module.flags.Flags.nfcHceLatencyEvents()).thenReturn(true);
187 
188         mHandler.post(() -> {
189             mHandler.handleMessage(msg);
190             verify(mSampleService).getMessenger();
191         });
192     }
193 
194     @Test
testOnBinder()195     public void testOnBinder() {
196         Messenger messenger = mock(Messenger.class);
197         when(mSampleService.getMessenger()).thenReturn(messenger);
198 
199         mSampleService.onBind(mock(Intent.class));
200         verify(messenger).getBinder();
201     }
202 
203     @Test
testNfcService()204     public void testNfcService() {
205         Messenger nfcService = mock(Messenger.class);
206         mSampleService.setNfcService(nfcService);
207 
208         assertEquals(nfcService, mSampleService.getNfcService());
209     }
210 }
211