Merge "Use the system property for the HdmiControlService configuration." into lmp-dev
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 2ff657f..47b0794 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -309,7 +309,8 @@
         // TODO: Return immediately if the operation is triggered by <Text/Image View On>
         // and this is the first notification about the active input after power-on
         // (switch to HDMI didn't happen so far but is expected to happen soon).
-        int oldPath = mService.portIdToPath(getActivePortId());
+        int oldPath = getActivePortId() != Constants.INVALID_PORT_ID
+                ? mService.portIdToPath(getActivePortId()) : getDeviceInfo().getPhysicalAddress();
         int newPath = mService.portIdToPath(portId);
         HdmiCecMessage routingChange =
                 HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath);
@@ -336,11 +337,11 @@
         if (!action.isEmpty()) {
             action.get(0).processKeyEvent(keyCode, isPressed);
         } else {
-            if (isPressed) {
+            if (isPressed && getActiveSource().isValid()) {
                 int logicalAddress = getActiveSource().logicalAddress;
                 addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode));
             } else {
-                Slog.w(TAG, "Discard key release event");
+                Slog.w(TAG, "Discard key event: " + keyCode + " pressed:" + isPressed);
             }
         }
     }
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 7f12489..c916507 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -565,14 +565,7 @@
             @Override
             public void onAudioPortListUpdate(AudioPort[] portList) {
                 synchronized (mImplLock) {
-                    updateAudioSinkLocked();
-                    if (mInfo.getAudioType() != AudioManager.DEVICE_NONE && mAudioSource == null) {
-                        mAudioSource = findAudioDevicePort(mInfo.getAudioType(),
-                                mInfo.getAudioAddress());
-                        if (mActiveConfig != null) {
-                            updateAudioPatchLocked();
-                        }
-                    }
+                    updateAudioConfigLocked();
                 }
             }
 
@@ -671,14 +664,7 @@
                 if (surface == null && mActiveConfig == null) {
                     return false;
                 }
-                if (mAudioSource != null && mAudioSink != null) {
-                    if (surface != null) {
-                        updateAudioPatchLocked();
-                    } else {
-                        mAudioManager.releaseAudioPatch(mAudioPatch);
-                        mAudioPatch = null;
-                    }
-                }
+
                 int result = TvInputHal.ERROR_UNKNOWN;
                 if (surface == null) {
                     result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig);
@@ -696,15 +682,24 @@
                         mActiveConfig = config;
                     }
                 }
+                updateAudioConfigLocked();
                 return result == TvInputHal.SUCCESS;
             }
         }
 
-        private void updateAudioPatchLocked() {
-            if (mAudioSource == null || mAudioSink == null) {
+        /**
+         * Update audio configuration (source, sink, patch) all up to current state.
+         */
+        private void updateAudioConfigLocked() {
+            boolean sinkUpdated = updateAudioSinkLocked();
+            boolean sourceUpdated = updateAudioSourceLocked();
+            // We can't do updated = updateAudioSinkLocked() || updateAudioSourceLocked() here
+            // because Java won't evaluate the latter if the former is true.
+
+            if (mAudioSource == null || mAudioSink == null || mActiveConfig == null) {
                 if (mAudioPatch != null) {
-                    throw new IllegalStateException("Audio patch should be null if audio source "
-                            + "or sink is null.");
+                    mAudioManager.releaseAudioPatch(mAudioPatch);
+                    mAudioPatch = null;
                 }
                 return;
             }
@@ -744,7 +739,7 @@
             AudioPortConfig sourceConfig = mAudioSource.activeConfig();
             AudioPortConfig sinkConfig = mAudioSink.activeConfig();
             AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch };
-            boolean shouldRecreateAudioPatch = false;
+            boolean shouldRecreateAudioPatch = sourceUpdated || sinkUpdated;
             if (sinkConfig == null
                     || (mDesiredSamplingRate != 0
                             && sinkConfig.samplingRate() != mDesiredSamplingRate)
@@ -778,7 +773,7 @@
                     throw new IllegalStateException("Device already released.");
                 }
                 mVolume = volume;
-                updateAudioPatchLocked();
+                updateAudioConfigLocked();
             }
         }
 
@@ -827,10 +822,21 @@
             }
         }
 
-        private void updateAudioSinkLocked() {
+        private boolean updateAudioSourceLocked() {
             if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) {
-                return;
+                return false;
             }
+            AudioDevicePort previousSource = mAudioSource;
+            mAudioSource = findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress());
+            return mAudioSource == null ? (previousSource != null)
+                    : !mAudioSource.equals(previousSource);
+        }
+
+        private boolean updateAudioSinkLocked() {
+            if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) {
+                return false;
+            }
+            AudioDevicePort previousSink = mAudioSink;
             if (mOverrideAudioType == AudioManager.DEVICE_NONE) {
                 mAudioSink = findAudioSinkFromAudioPolicy();
             } else {
@@ -840,12 +846,12 @@
                     mAudioSink = audioSink;
                 }
             }
+            return mAudioSink == null ? (previousSink != null) : !mAudioSink.equals(previousSink);
         }
 
         private void handleAudioSinkUpdated() {
             synchronized (mImplLock) {
-                updateAudioSinkLocked();
-                updateAudioPatchLocked();
+                updateAudioConfigLocked();
             }
         }
 
@@ -855,15 +861,12 @@
             synchronized (mImplLock) {
                 mOverrideAudioType = audioType;
                 mOverrideAudioAddress = audioAddress;
-                updateAudioSinkLocked();
 
                 mDesiredSamplingRate = samplingRate;
                 mDesiredChannelMask = channelMask;
                 mDesiredFormat = format;
 
-                if (mAudioPatch != null) {
-                    updateAudioPatchLocked();
-                }
+                updateAudioConfigLocked();
             }
         }
     }