Merge "Correct default payment selection behavior"
diff --git a/nci/jni/HciEventManager.cpp b/nci/jni/HciEventManager.cpp
index 0921f53..1365a0d 100644
--- a/nci/jni/HciEventManager.cpp
+++ b/nci/jni/HciEventManager.cpp
@@ -148,7 +148,7 @@
   } else if (eventData->rcvd_evt.pipe == sSimPipe) {
     evtSrc = "SIM1";
   } else {
-    LOG(ERROR) << "Incorrect Pipe Id";
+    LOG(WARNING) << "Incorrect Pipe Id";
     return;
   }
 
diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp
index 9329d9f..28ae464 100644
--- a/nci/jni/NativeNfcManager.cpp
+++ b/nci/jni/NativeNfcManager.cpp
@@ -862,6 +862,24 @@
                           android::gCachedNfcManagerNotifyHwErrorReported);
         {
           DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+              "%s: aborting  sNfaEnableDisablePollingEvent", __func__);
+          SyncEventGuard guard(sNfaEnableDisablePollingEvent);
+          sNfaEnableDisablePollingEvent.notifyOne();
+        }
+        {
+          DLOG_IF(INFO, nfc_debug_enabled)
+              << StringPrintf("%s: aborting  sNfaEnableEvent", __func__);
+          SyncEventGuard guard(sNfaEnableEvent);
+          sNfaEnableEvent.notifyOne();
+        }
+        {
+          DLOG_IF(INFO, nfc_debug_enabled)
+              << StringPrintf("%s: aborting  sNfaDisableEvent", __func__);
+          SyncEventGuard guard(sNfaDisableEvent);
+          sNfaDisableEvent.notifyOne();
+        }
+        {
+          DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
               "%s: aborting  sNfaSetPowerSubState", __func__);
           SyncEventGuard guard(sNfaSetPowerSubState);
           sNfaSetPowerSubState.notifyOne();
@@ -872,7 +890,12 @@
           SyncEventGuard guard(sNfaSetConfigEvent);
           sNfaSetConfigEvent.notifyOne();
         }
-
+        {
+          DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+              "%s: aborting  sNfaGetConfigEvent", __func__);
+          SyncEventGuard guard(sNfaGetConfigEvent);
+          sNfaGetConfigEvent.notifyOne();
+        }
       } else {
         nativeNfcTag_abortWaits();
         NfcTag::getInstance().abort();
diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp
index ddae94e..677a8a9 100644
--- a/nci/jni/NativeNfcTag.cpp
+++ b/nci/jni/NativeNfcTag.cpp
@@ -863,7 +863,7 @@
   NfcTag::getInstance().resetAllTransceiveTimeouts();
 
   if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
-    LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__);
+    LOG(WARNING) << StringPrintf("%s: tag already deactivated", __func__);
     goto TheEnd;
   }
 
diff --git a/nci/jni/RoutingManager.cpp b/nci/jni/RoutingManager.cpp
index 1e19b9c..4ea3cf0 100644
--- a/nci/jni/RoutingManager.cpp
+++ b/nci/jni/RoutingManager.cpp
@@ -340,7 +340,7 @@
     DLOG_IF(INFO, nfc_debug_enabled) << fn << ": removed AID";
     return true;
   } else {
-    LOG(ERROR) << fn << ": failed to remove AID";
+    LOG(WARNING) << fn << ": failed to remove AID";
     return false;
   }
 }
diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java
index 041ebb1..ad1759a 100644
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -46,6 +46,7 @@
 import android.nfc.INfcAdapter;
 import android.nfc.INfcAdapterExtras;
 import android.nfc.INfcCardEmulation;
+import android.nfc.INfcControllerAlwaysOnListener;
 import android.nfc.INfcDta;
 import android.nfc.INfcFCardEmulation;
 import android.nfc.INfcTag;
@@ -106,11 +107,14 @@
 import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Scanner;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
@@ -165,7 +169,6 @@
     static final int MSG_PREFERRED_PAYMENT_CHANGED = 18;
     static final int MSG_TOAST_DEBOUNCE_EVENT = 19;
     static final int MSG_DELAY_POLLING = 20;
-    static final int MSG_ALWAYS_ON_STATE_CHANGED = 21;
 
     static final String MSG_ROUTE_AID_PARAM_TAG = "power";
 
@@ -349,6 +352,8 @@
     boolean mIsVrModeEnabled;
 
     private final boolean mIsAlwaysOnSupported;
+    private final Set<INfcControllerAlwaysOnListener> mAlwaysOnListeners =
+            Collections.synchronizedSet(new HashSet<>());
 
     public static NfcService getInstance() {
         return sService;
@@ -997,7 +1002,20 @@
                     return;
                 }
                 mAlwaysOnState = newState;
-                sendMessage(NfcService.MSG_ALWAYS_ON_STATE_CHANGED, mAlwaysOnState);
+                if (mAlwaysOnState == NfcAdapter.STATE_OFF
+                        || mAlwaysOnState == NfcAdapter.STATE_ON) {
+                    synchronized (mAlwaysOnListeners) {
+                        for (INfcControllerAlwaysOnListener listener
+                                : mAlwaysOnListeners) {
+                            try {
+                                listener.onControllerAlwaysOnChanged(
+                                        mAlwaysOnState == NfcAdapter.STATE_ON);
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "error in updateAlwaysOnState");
+                            }
+                        }
+                    }
+                }
             }
         }
 
@@ -1615,6 +1633,24 @@
             NfcPermissions.enforceSetControllerAlwaysOnPermissions(mContext);
             return mIsAlwaysOnSupported;
         }
+
+        @Override
+        public void registerControllerAlwaysOnListener(
+                INfcControllerAlwaysOnListener listener) throws RemoteException {
+            NfcPermissions.enforceSetControllerAlwaysOnPermissions(mContext);
+            if (!mIsAlwaysOnSupported) return;
+
+            mAlwaysOnListeners.add(listener);
+        }
+
+        @Override
+        public void unregisterControllerAlwaysOnListener(
+                INfcControllerAlwaysOnListener listener) throws RemoteException {
+            NfcPermissions.enforceSetControllerAlwaysOnPermissions(mContext);
+            if (!mIsAlwaysOnSupported) return;
+
+            mAlwaysOnListeners.remove(listener);
+        }
     }
 
     final class ReaderModeDeathRecipient implements IBinder.DeathRecipient {
@@ -2738,15 +2774,6 @@
                     }
                     if (DBG) Log.d(TAG, "Polling is started");
                     break;
-                case MSG_ALWAYS_ON_STATE_CHANGED:
-                    int mSendState = (Integer) msg.obj;
-                    Intent intent = new Intent(NfcAdapter.ACTION_ALWAYS_ON_STATE_CHANGED);
-                    intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                    intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mSendState);
-                    sendNfcEeAccessProtectedBroadcast(intent);
-                    Log.d(TAG, "MSG_ALWAYS_ON_STATE_CHANGED " + mSendState);
-                    break;
-
                 default:
                     Log.e(TAG, "Unknown message received");
                     break;
diff --git a/tests/unit/src/com/android/nfc/NfcStateTest.java b/tests/unit/src/com/android/nfc/NfcStateTest.java
index 5a3667c..26f93a4 100644
--- a/tests/unit/src/com/android/nfc/NfcStateTest.java
+++ b/tests/unit/src/com/android/nfc/NfcStateTest.java
@@ -23,6 +23,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.nfc.NfcAdapter;
+import android.nfc.NfcAdapter.ControllerAlwaysOnListener;
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
@@ -34,6 +35,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.Executor;
+
 @RunWith(AndroidJUnit4.class)
 public final class NfcStateTest {
 
@@ -43,7 +46,15 @@
     private NfcAdapter mNfcAdapter;
     private BroadcastReceiver mAdapterStateChangedReceiver;
     private int mState;
+    private boolean mIsAlwaysOnEnabled;
     private boolean mNfcSupported;
+    private ControllerAlwaysOnListener mListener;
+
+    class SynchronousExecutor implements Executor {
+        public void execute(Runnable r) {
+            r.run();
+        }
+    }
 
     @Before
     public void setUp() {
@@ -64,11 +75,20 @@
         } else {
             mState = NfcAdapter.STATE_OFF;
         }
+        if (mNfcAdapter.isControllerAlwaysOnSupported()) {
+            mListener = new AlwaysOnStateListener();
+            mNfcAdapter.registerControllerAlwaysOnListener(new SynchronousExecutor(),
+                    mListener);
+            mIsAlwaysOnEnabled = mNfcAdapter.isControllerAlwaysOn();
+        }
     }
 
     @After
     public void tearDown() throws Exception {
         mContext.unregisterReceiver(mAdapterStateChangedReceiver);
+        if (mNfcAdapter.isControllerAlwaysOnSupported()) {
+            mNfcAdapter.unregisterControllerAlwaysOnListener(mListener);
+        }
     }
 
     @Test
@@ -307,6 +327,13 @@
             }
         }
     }
+    private class AlwaysOnStateListener implements ControllerAlwaysOnListener {
+        @Override
+        public void onControllerAlwaysOnChanged(boolean isEnabled) {
+            Log.i(TAG, "onControllerAlwaysOnChanged, mIsAlwaysOnEnabled = " + isEnabled);
+            mIsAlwaysOnEnabled = isEnabled;
+        }
+    }
     private void wait_for_state(int targetState) {
         int duration = 100;
         for (int i = 0; i < MAX_TIMEOUT_MS / duration; i++) {
@@ -318,7 +345,7 @@
         int duration = 1000;
         for (int i = 0; i < MAX_TIMEOUT_MS / duration; i++) {
             msleep(duration);
-            if (isEnabled == mNfcAdapter.isControllerAlwaysOn()) break;
+            if (isEnabled == mIsAlwaysOnEnabled) break;
         }
     }