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.google.common.truth.Truth.assertThat; 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.nfc.NfcAdapter.ControllerAlwaysOnListener; 27 import android.util.Log; 28 29 import androidx.test.InstrumentationRegistry; 30 import androidx.test.ext.junit.runners.AndroidJUnit4; 31 32 import org.junit.After; 33 import org.junit.Assert; 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 import java.util.concurrent.Executor; 39 40 @RunWith(AndroidJUnit4.class) 41 public final class NfcStateTest { 42 43 private static final String TAG = NfcStateTest.class.getSimpleName(); 44 private static final int MAX_TIMEOUT_MS = 20000; 45 private Context mContext; 46 private NfcAdapter mNfcAdapter; 47 private BroadcastReceiver mAdapterStateChangedReceiver; 48 private int mState; 49 private boolean mIsAlwaysOnEnabled; 50 private boolean mNfcSupported; 51 private ControllerAlwaysOnListener mListener; 52 53 class SynchronousExecutor implements Executor { execute(Runnable r)54 public void execute(Runnable r) { 55 r.run(); 56 } 57 } 58 59 @Before setUp()60 public void setUp() { 61 mContext = InstrumentationRegistry.getTargetContext(); 62 IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); 63 mAdapterStateChangedReceiver = new AdapterStateChangedReceiver(); 64 mContext.registerReceiver(mAdapterStateChangedReceiver, filter); 65 PackageManager pm = mContext.getPackageManager(); 66 if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_ANY)) { 67 mNfcSupported = false; 68 return; 69 } 70 mNfcSupported = true; 71 mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext); 72 Assert.assertNotNull(mNfcAdapter); 73 if (mNfcAdapter.isEnabled()) { 74 mState = NfcAdapter.STATE_ON; 75 } else { 76 mState = NfcAdapter.STATE_OFF; 77 } 78 if (mNfcAdapter.isControllerAlwaysOnSupported()) { 79 mListener = new AlwaysOnStateListener(); 80 mNfcAdapter.registerControllerAlwaysOnListener(new SynchronousExecutor(), 81 mListener); 82 mIsAlwaysOnEnabled = mNfcAdapter.isControllerAlwaysOn(); 83 } 84 } 85 86 @After tearDown()87 public void tearDown() throws Exception { 88 mContext.unregisterReceiver(mAdapterStateChangedReceiver); 89 if (mNfcSupported && mNfcAdapter.isControllerAlwaysOnSupported()) { 90 mNfcAdapter.unregisterControllerAlwaysOnListener(mListener); 91 } 92 } 93 94 @Test testSetControllerAlwaysOnTrueFromFalseWhenDisabled()95 public void testSetControllerAlwaysOnTrueFromFalseWhenDisabled() { 96 if (!mNfcSupported || !mNfcAdapter.isControllerAlwaysOnSupported()) return; 97 if (mNfcAdapter.isControllerAlwaysOn()) { 98 mNfcAdapter.setControllerAlwaysOn(false); 99 wait_for_always_on(false); 100 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(false); 101 } 102 if (mNfcAdapter.isEnabled()) { 103 mNfcAdapter.disable(); 104 wait_for_state(NfcAdapter.STATE_OFF); 105 } 106 mNfcAdapter.setControllerAlwaysOn(true); 107 wait_for_always_on(true); 108 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(true); 109 } 110 111 @Test testSetControllerAlwaysOnFalseFromTrueWhenDisabled()112 public void testSetControllerAlwaysOnFalseFromTrueWhenDisabled() { 113 if (!mNfcSupported || !mNfcAdapter.isControllerAlwaysOnSupported()) return; 114 if (!mNfcAdapter.isControllerAlwaysOn()) { 115 mNfcAdapter.setControllerAlwaysOn(true); 116 wait_for_always_on(true); 117 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(true); 118 } 119 if (mNfcAdapter.isEnabled()) { 120 mNfcAdapter.disable(); 121 wait_for_state(NfcAdapter.STATE_OFF); 122 } 123 mNfcAdapter.setControllerAlwaysOn(false); 124 wait_for_always_on(false); 125 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(false); 126 } 127 128 @Test testSetControllerAlwaysOnFalseFromFalseWhenDisabled()129 public void testSetControllerAlwaysOnFalseFromFalseWhenDisabled() { 130 if (!mNfcSupported || !mNfcAdapter.isControllerAlwaysOnSupported()) return; 131 if (!mNfcAdapter.isControllerAlwaysOn()) { 132 mNfcAdapter.setControllerAlwaysOn(false); 133 wait_for_always_on(false); 134 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(false); 135 } 136 if (mNfcAdapter.isEnabled()) { 137 mNfcAdapter.disable(); 138 wait_for_state(NfcAdapter.STATE_OFF); 139 } 140 mNfcAdapter.setControllerAlwaysOn(false); 141 wait_for_always_on(false); 142 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(false); 143 } 144 145 @Test testSetControllerAlwaysOnTrueFromTrueWhenDisabled()146 public void testSetControllerAlwaysOnTrueFromTrueWhenDisabled() { 147 if (!mNfcSupported || !mNfcAdapter.isControllerAlwaysOnSupported()) return; 148 if (!mNfcAdapter.isControllerAlwaysOn()) { 149 mNfcAdapter.setControllerAlwaysOn(true); 150 wait_for_always_on(true); 151 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(true); 152 } 153 if (mNfcAdapter.isEnabled()) { 154 mNfcAdapter.disable(); 155 wait_for_state(NfcAdapter.STATE_OFF); 156 } 157 mNfcAdapter.setControllerAlwaysOn(true); 158 wait_for_always_on(true); 159 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(true); 160 } 161 162 @Test testSetControllerAlwaysOnTrueFromFalseWhenEnabled()163 public void testSetControllerAlwaysOnTrueFromFalseWhenEnabled() { 164 if (!mNfcSupported || !mNfcAdapter.isControllerAlwaysOnSupported()) return; 165 if (mNfcAdapter.isControllerAlwaysOn()) { 166 mNfcAdapter.setControllerAlwaysOn(false); 167 wait_for_always_on(false); 168 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(false); 169 } 170 if (!mNfcAdapter.isEnabled()) { 171 mNfcAdapter.enable(); 172 wait_for_state(NfcAdapter.STATE_ON); 173 } 174 mNfcAdapter.setControllerAlwaysOn(true); 175 wait_for_always_on(true); 176 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(true); 177 } 178 179 @Test testSetAlwaysOnFalseFromTrueWhenEnabled()180 public void testSetAlwaysOnFalseFromTrueWhenEnabled() { 181 if (!mNfcSupported || !mNfcAdapter.isControllerAlwaysOnSupported()) return; 182 if (!mNfcAdapter.isControllerAlwaysOn()) { 183 mNfcAdapter.setControllerAlwaysOn(true); 184 wait_for_always_on(true); 185 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(true); 186 } 187 if (!mNfcAdapter.isEnabled()) { 188 mNfcAdapter.enable(); 189 wait_for_state(NfcAdapter.STATE_ON); 190 } 191 mNfcAdapter.setControllerAlwaysOn(false); 192 wait_for_always_on(false); 193 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(false); 194 } 195 196 @Test testSetControllerAlwaysOnFalseFromFalseWhenEnabled()197 public void testSetControllerAlwaysOnFalseFromFalseWhenEnabled() { 198 if (!mNfcSupported || !mNfcAdapter.isControllerAlwaysOnSupported()) return; 199 if (!mNfcAdapter.isControllerAlwaysOn()) { 200 mNfcAdapter.setControllerAlwaysOn(false); 201 wait_for_always_on(false); 202 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(false); 203 } 204 if (!mNfcAdapter.isEnabled()) { 205 mNfcAdapter.enable(); 206 wait_for_state(NfcAdapter.STATE_ON); 207 } 208 mNfcAdapter.setControllerAlwaysOn(false); 209 wait_for_always_on(false); 210 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(false); 211 } 212 213 @Test testSetControllerAlwaysOnTrueFromTrueWhenEnabled()214 public void testSetControllerAlwaysOnTrueFromTrueWhenEnabled() { 215 if (!mNfcSupported || !mNfcAdapter.isControllerAlwaysOnSupported()) return; 216 if (!mNfcAdapter.isControllerAlwaysOn()) { 217 mNfcAdapter.setControllerAlwaysOn(true); 218 wait_for_always_on(true); 219 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(true); 220 } 221 if (!mNfcAdapter.isEnabled()) { 222 mNfcAdapter.enable(); 223 wait_for_state(NfcAdapter.STATE_ON); 224 } 225 mNfcAdapter.setControllerAlwaysOn(true); 226 wait_for_always_on(true); 227 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(true); 228 } 229 230 @Test testEnableWhenSetControllerAlwaysOnTrueAndDisabled()231 public void testEnableWhenSetControllerAlwaysOnTrueAndDisabled() { 232 if (!mNfcSupported || !mNfcAdapter.isControllerAlwaysOnSupported()) return; 233 if (!mNfcAdapter.isControllerAlwaysOn()) { 234 mNfcAdapter.setControllerAlwaysOn(true); 235 wait_for_always_on(true); 236 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(true); 237 } 238 if (mNfcAdapter.isEnabled()) { 239 mNfcAdapter.disable(); 240 wait_for_state(NfcAdapter.STATE_OFF); 241 assertThat(mNfcAdapter.isEnabled()).isEqualTo(false); 242 } 243 mNfcAdapter.enable(); 244 wait_for_state(NfcAdapter.STATE_ON); 245 assertThat(mState).isEqualTo(NfcAdapter.STATE_ON); 246 assertThat(mNfcAdapter.isEnabled()).isEqualTo(true); 247 } 248 249 @Test testDisableWhenSetControllerAlwaysOnTrueAndEnabled()250 public void testDisableWhenSetControllerAlwaysOnTrueAndEnabled() { 251 if (!mNfcSupported || !mNfcAdapter.isControllerAlwaysOnSupported()) return; 252 if (!mNfcAdapter.isControllerAlwaysOn()) { 253 mNfcAdapter.setControllerAlwaysOn(true); 254 wait_for_always_on(true); 255 assertThat(mNfcAdapter.isControllerAlwaysOn()).isEqualTo(true); 256 } 257 if (!mNfcAdapter.isEnabled()) { 258 mNfcAdapter.enable(); 259 wait_for_state(NfcAdapter.STATE_ON); 260 assertThat(mNfcAdapter.isEnabled()).isEqualTo(true); 261 } 262 mNfcAdapter.disable(); 263 wait_for_state(NfcAdapter.STATE_OFF); 264 assertThat(mState).isEqualTo(NfcAdapter.STATE_OFF); 265 assertThat(mNfcAdapter.isEnabled()).isEqualTo(false); 266 } 267 268 @Test testDisableWhenEnabled()269 public void testDisableWhenEnabled() { 270 if (!mNfcSupported) return; 271 if (!mNfcAdapter.isEnabled()) { 272 mNfcAdapter.enable(); 273 wait_for_state(NfcAdapter.STATE_ON); 274 } 275 mNfcAdapter.disable(); 276 wait_for_state(NfcAdapter.STATE_OFF); 277 assertThat(mState).isEqualTo(NfcAdapter.STATE_OFF); 278 assertThat(mNfcAdapter.isEnabled()).isEqualTo(false); 279 } 280 281 @Test testEnableWhenDisabled()282 public void testEnableWhenDisabled() { 283 if (!mNfcSupported) return; 284 if (mNfcAdapter.isEnabled()) { 285 mNfcAdapter.disable(); 286 wait_for_state(NfcAdapter.STATE_OFF); 287 } 288 mNfcAdapter.enable(); 289 wait_for_state(NfcAdapter.STATE_ON); 290 assertThat(mState).isEqualTo(NfcAdapter.STATE_ON); 291 assertThat(mNfcAdapter.isEnabled()).isEqualTo(true); 292 } 293 294 @Test testDisableWhenDisabled()295 public void testDisableWhenDisabled() { 296 if (!mNfcSupported) return; 297 if (mNfcAdapter.isEnabled()) { 298 mNfcAdapter.disable(); 299 wait_for_state(NfcAdapter.STATE_OFF); 300 } 301 mNfcAdapter.disable(); 302 wait_for_state(NfcAdapter.STATE_OFF); 303 assertThat(mState).isEqualTo(NfcAdapter.STATE_OFF); 304 assertThat(mNfcAdapter.isEnabled()).isEqualTo(false); 305 } 306 307 @Test testEnableWhenEnabled()308 public void testEnableWhenEnabled() { 309 if (!mNfcSupported) return; 310 if (!mNfcAdapter.isEnabled()) { 311 mNfcAdapter.enable(); 312 wait_for_state(NfcAdapter.STATE_ON); 313 } 314 mNfcAdapter.enable(); 315 wait_for_state(NfcAdapter.STATE_ON); 316 assertThat(mState).isEqualTo(NfcAdapter.STATE_ON); 317 assertThat(mNfcAdapter.isEnabled()).isEqualTo(true); 318 } 319 320 private class AdapterStateChangedReceiver extends BroadcastReceiver { 321 @Override onReceive(Context context, Intent intent)322 public void onReceive(Context context, Intent intent) { 323 if (NfcAdapter.ACTION_ADAPTER_STATE_CHANGED.equals(intent.getAction())) { 324 mState = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, 325 NfcAdapter.STATE_OFF); 326 Log.i(TAG, "mState = " + mState); 327 } 328 } 329 } 330 private class AlwaysOnStateListener implements ControllerAlwaysOnListener { 331 @Override onControllerAlwaysOnChanged(boolean isEnabled)332 public void onControllerAlwaysOnChanged(boolean isEnabled) { 333 Log.i(TAG, "onControllerAlwaysOnChanged, mIsAlwaysOnEnabled = " + isEnabled); 334 mIsAlwaysOnEnabled = isEnabled; 335 } 336 } wait_for_state(int targetState)337 private void wait_for_state(int targetState) { 338 int duration = 100; 339 for (int i = 0; i < MAX_TIMEOUT_MS / duration; i++) { 340 msleep(duration); 341 if (mState == targetState) break; 342 } 343 } wait_for_always_on(boolean isEnabled)344 private void wait_for_always_on(boolean isEnabled) { 345 int duration = 1000; 346 for (int i = 0; i < MAX_TIMEOUT_MS / duration; i++) { 347 msleep(duration); 348 if (isEnabled == mIsAlwaysOnEnabled) break; 349 } 350 } 351 msleep(int millis)352 private void msleep(int millis) { 353 try { 354 Thread.sleep(millis); 355 } catch (InterruptedException e) { 356 } 357 } 358 } 359