Merge "Reduce time consuming when a lot of audio port event happen continually."
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 186b265..dab7632a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4119,7 +4119,15 @@
                         Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
                         return status;
                     }
-                } while (patchGeneration[0] != portGeneration[0]);
+                    // Loop until patch generation is the same as port generation unless audio ports
+                    // and audio patches are not null.
+                } while (patchGeneration[0] != portGeneration[0]
+                        && (ports == null || patches == null));
+                // If the patch generation doesn't equal port generation, return ERROR here in case
+                // of mismatch between audio ports and audio patches.
+                if (patchGeneration[0] != portGeneration[0]) {
+                    return ERROR;
+                }
 
                 for (int i = 0; i < newPatches.size(); i++) {
                     for (int j = 0; j < newPatches.get(i).sources().length; j++) {
diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java
index c152245..ac3904a 100644
--- a/media/java/android/media/AudioPortEventHandler.java
+++ b/media/java/android/media/AudioPortEventHandler.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import java.util.ArrayList;
@@ -30,6 +31,7 @@
 
 class AudioPortEventHandler {
     private Handler mHandler;
+    private HandlerThread mHandlerThread;
     private final ArrayList<AudioManager.OnAudioPortUpdateListener> mListeners =
             new ArrayList<AudioManager.OnAudioPortUpdateListener>();
 
@@ -40,6 +42,8 @@
     private static final int AUDIOPORT_EVENT_SERVICE_DIED = 3;
     private static final int AUDIOPORT_EVENT_NEW_LISTENER = 4;
 
+    private static final long RESCHEDULE_MESSAGE_DELAY_MS = 100;
+
     /**
      * Accessed by native methods: JNI Callback context.
      */
@@ -51,11 +55,12 @@
             if (mHandler != null) {
                 return;
             }
-            // find the looper for our new event handler
-            Looper looper = Looper.getMainLooper();
+            // create a new thread for our new event handler
+            mHandlerThread = new HandlerThread(TAG);
+            mHandlerThread.start();
 
-            if (looper != null) {
-                mHandler = new Handler(looper) {
+            if (mHandlerThread.getLooper() != null) {
+                mHandler = new Handler(mHandlerThread.getLooper()) {
                     @Override
                     public void handleMessage(Message msg) {
                         ArrayList<AudioManager.OnAudioPortUpdateListener> listeners;
@@ -86,6 +91,12 @@
                         if (msg.what != AUDIOPORT_EVENT_SERVICE_DIED) {
                             int status = AudioManager.updateAudioPortCache(ports, patches, null);
                             if (status != AudioManager.SUCCESS) {
+                                // Since audio ports and audio patches are not null, the return
+                                // value could be ERROR due to inconsistency between port generation
+                                // and patch generation. In this case, we need to reschedule the
+                                // message to make sure the native callback is done.
+                                sendMessageDelayed(obtainMessage(msg.what, msg.obj),
+                                        RESCHEDULE_MESSAGE_DELAY_MS);
                                 return;
                             }
                         }
@@ -132,6 +143,9 @@
     @Override
     protected void finalize() {
         native_finalize();
+        if (mHandlerThread.isAlive()) {
+            mHandlerThread.quit();
+        }
     }
     private native void native_finalize();
 
@@ -168,6 +182,10 @@
             Handler handler = eventHandler.handler();
             if (handler != null) {
                 Message m = handler.obtainMessage(what, arg1, arg2, obj);
+                if (what != AUDIOPORT_EVENT_NEW_LISTENER) {
+                    // Except AUDIOPORT_EVENT_NEW_LISTENER, we can only respect the last message.
+                    handler.removeMessages(what);
+                }
                 handler.sendMessage(m);
             }
         }