Fix issue 1795088       Improve audio routing code

Initial commit for review.
Integrated comments after patch set 1 review.
Fixed lockup in AudioFlinger::ThreadBase::exit()
Fixed lockup when playing tone with AudioPlocyService startTone()
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
index 9b0a2d4..bee3108 100644
--- a/services/java/com/android/server/HeadsetObserver.java
+++ b/services/java/com/android/server/HeadsetObserver.java
@@ -41,10 +41,16 @@
     private static final String HEADSET_STATE_PATH = "/sys/class/switch/h2w/state";
     private static final String HEADSET_NAME_PATH = "/sys/class/switch/h2w/name";
 
+    private static final int BIT_HEADSET = (1 << 0);
+    private static final int BIT_HEADSET_NO_MIC = (1 << 1);
+    private static final int BIT_TTY = (1 << 2);
+    private static final int BIT_FM_HEADSET = (1 << 3);
+    private static final int BIT_FM_SPEAKER = (1 << 4);
+
     private int mHeadsetState;
+    private int mPrevHeadsetState;
     private String mHeadsetName;
-    private boolean mAudioRouteNeedsUpdate;
-    private AudioManager mAudioManager;
+    private boolean mPendingIntent;
 
     private final Context mContext;
     private final WakeLock mWakeLock;  // held while there is a pending route change
@@ -76,6 +82,7 @@
 
         String newName = mHeadsetName;
         int newState = mHeadsetState;
+        mPrevHeadsetState = mHeadsetState;
         try {
             FileReader file = new FileReader(HEADSET_STATE_PATH);
             int len = file.read(buffer, 0, 1024);
@@ -91,20 +98,25 @@
             Log.e(TAG, "" , e);
         }
 
-        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         update(newName, newState);
     }
 
     private synchronized final void update(String newName, int newState) {
         if (newName != mHeadsetName || newState != mHeadsetState) {
-            boolean isUnplug = (newState == 0 && mHeadsetState == 1);
+            boolean isUnplug = false;
+            if ( (mHeadsetState & BIT_HEADSET) > 0 || (mHeadsetState & BIT_HEADSET_NO_MIC) > 0) {
+                if ((newState & BIT_HEADSET) == 0 && (newState & BIT_HEADSET_NO_MIC) == 0)
+                    isUnplug = true;
+            }
             mHeadsetName = newName;
+            mPrevHeadsetState = mHeadsetState;
             mHeadsetState = newState;
-            mAudioRouteNeedsUpdate = true;
-
-            sendIntent(isUnplug);
+            mPendingIntent = true;
 
             if (isUnplug) {
+                Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+                mContext.sendBroadcast(intent);
+
                 // It can take hundreds of ms flush the audio pipeline after
                 // apps pause audio playback, but audio route changes are
                 // immediate, so delay the route change by 1000ms.
@@ -113,12 +125,13 @@
                 mWakeLock.acquire();
                 mHandler.sendEmptyMessageDelayed(0, 1000);
             } else {
-                updateAudioRoute();
+                sendIntent();
+                mPendingIntent = false;
             }
         }
     }
 
-    private synchronized final void sendIntent(boolean isUnplug) {
+    private synchronized final void sendIntent() {
         //  Pack up the values and broadcast them to everyone
         Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -128,24 +141,15 @@
 
         // TODO: Should we require a permission?
         ActivityManagerNative.broadcastStickyIntent(intent, null);
-
-        if (isUnplug) {
-            intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
-            mContext.sendBroadcast(intent);
-        }
-    }
-
-    private synchronized final void updateAudioRoute() {
-        if (mAudioRouteNeedsUpdate) {
-            mAudioManager.setWiredHeadsetOn(mHeadsetState == 1);
-            mAudioRouteNeedsUpdate = false;
-        }
     }
 
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
-            updateAudioRoute();
+            if (mPendingIntent) {
+                sendIntent();
+                mPendingIntent = false;
+            }
             mWakeLock.release();
         }
     };