Merge "Fixing missing current api.txt related to CL/495976."
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index 85af3d1..f46be45 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -69,6 +69,34 @@
         }
     }
 
+    /**
+     * Set system audio volume
+     *
+     * @param oldIndex current volume index
+     * @param newIndex volume index to be set
+     * @param maxIndex maximum volume index
+     */
+    public void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex) {
+        try {
+            mService.setSystemAudioVolume(oldIndex, newIndex, maxIndex);
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to set volume: ", e);
+        }
+    }
+
+    /**
+     * Set system audio mute status
+     *
+     * @param mute {@code true} if muted; otherwise, {@code false}
+     */
+    public void setSystemAudioMute(boolean mute) {
+        try {
+            mService.setSystemAudioMute(mute);
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to set mute: ", e);
+        }
+    }
+
     private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
         return new IHdmiControlCallback.Stub() {
             @Override
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index f2948e7..6acd7b9 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -51,4 +51,6 @@
     void setControlEnabled(boolean enabled);
     void setArcMode(boolean enabled);
     void setOption(int option, int value);
+    oneway void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex);
+    oneway void setSystemAudioMute(boolean mute);
 }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 98a575a..8dfa227 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -340,6 +340,12 @@
     public static final int FLAG_SHOW_SILENT_HINT = 1 << 7;
 
     /**
+     * Indicates the volume call is for Hdmi Cec system audio volume
+     * @hide
+     */
+    public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8;
+
+    /**
      * Ringer mode that will be silent and will not vibrate. (This overrides the
      * vibrate setting.)
      *
@@ -2873,6 +2879,23 @@
     }
 
     /**
+     * Set Hdmi Cec system audio mode.
+     *
+     * @param on whether to be on system audio mode
+     * @param device out device type to be used for system audio mode.
+     *               Ignored if {@code on} is {@code false}
+     * @param name name of system audio device
+     * @hide
+     */
+    public void setHdmiSystemAudioSupported(boolean on, int device, String name) {
+        try {
+            getService().setHdmiSystemAudioSupported(on, device, name);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error setting system audio mode", e);
+        }
+    }
+
+    /**
      * Return codes for listAudioPorts(), createAudioPatch() ...
      */
 
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 628d35b..153ee31 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -43,6 +43,8 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiTvClient;
 import android.hardware.usb.UsbManager;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
@@ -572,6 +574,11 @@
             setRotationForAudioSystem();
         }
 
+        HdmiControlManager hdmiManager =
+                (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
+        // Null if device is not Tv.
+        mHdmiTvClient = hdmiManager.getTvClient();
+
         context.registerReceiver(mReceiver, intentFilter);
 
         mUseMasterVolume = context.getResources().getBoolean(
@@ -969,6 +976,21 @@
                         streamState,
                         0);
             }
+
+            // Check if volume update should be send to Hdmi system audio.
+            int newIndex = mStreamStates[streamType].getIndex(device);
+            if (mHdmiTvClient != null &&
+                streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
+                oldIndex != newIndex) {
+                int maxIndex = getStreamMaxVolume(streamType);
+                synchronized (mHdmiTvClient) {
+                    if (mHdmiSystemAudioSupported) {
+                        mHdmiTvClient.setSystemAudioVolume(
+                                (oldIndex + 5) / 10, (newIndex + 5) / 10, maxIndex);
+                    }
+                }
+            }
         }
         int index = mStreamStates[streamType].getIndex(device);
         sendVolumeUpdate(streamType, oldIndex, index, flags);
@@ -1069,6 +1091,19 @@
                 }
             }
 
+            if (mHdmiTvClient != null &&
+                streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
+                oldIndex != index) {
+                int maxIndex = getStreamMaxVolume(streamType);
+                synchronized (mHdmiTvClient) {
+                    if (mHdmiSystemAudioSupported) {
+                        mHdmiTvClient.setSystemAudioVolume(
+                                (oldIndex + 5) / 10, (index + 5) / 10, maxIndex);
+                    }
+                }
+            }
+
             flags &= ~AudioManager.FLAG_FIXED_VOLUME;
             if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
                     ((device & mFixedVolumeDevices) != 0)) {
@@ -1292,6 +1327,13 @@
         }
 
         if (isStreamAffectedByMute(streamType)) {
+            if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) {
+                synchronized (mHdmiTvClient) {
+                    if (mHdmiSystemAudioSupported) {
+                        mHdmiTvClient.setSystemAudioMute(state);
+                    }
+                }
+            }
             mStreamStates[streamType].mute(cb, state);
         }
     }
@@ -4701,6 +4743,64 @@
         }
     }
 
+    //==========================================================================================
+    // Hdmi Cec system audio mode.
+    // If Hdmi Cec's system audio mode is on, audio service should notify volume change
+    // to HdmiControlService so that audio recevier can handle volume change.
+    //==========================================================================================
+
+    // If HDMI-CEC system audio is supported
+    private boolean mHdmiSystemAudioSupported = false;
+    // Set only when device is tv.
+    private HdmiTvClient mHdmiTvClient;
+
+    @Override
+    public void setHdmiSystemAudioSupported(boolean on, int device, String name) {
+        if (mHdmiTvClient == null) {
+            Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
+            return;
+        }
+
+        if ((device & AudioSystem.DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO) == 0) {
+            Log.w(TAG, "Unsupported Hdmi-Cec system audio output:" + device);
+            return;
+        }
+
+        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+        int oldStreamDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
+        int oldIndex = streamState.getIndex(oldStreamDevice);
+
+        synchronized (mHdmiTvClient) {
+            mHdmiSystemAudioSupported = on;
+
+            // TODO: call AudioSystem.setForceUse(FORCE_FOR_MEDIA,
+            //         on ? AudioSystem.FORCE_SYSTEM_AUDIO_XXX : AudioSystem.FORCE_NONE;
+        }
+
+        int newStreamDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
+        boolean updateSpeakerVolume = false;
+        if (on) {
+            if ((oldStreamDevice & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
+                // Mute tv speaker. Note that set volume 0 instead of call mute() method because
+                // it's not possible to mute for a specific device.
+                streamState.setIndex(0, AudioSystem.DEVICE_OUT_SPEAKER);
+                updateSpeakerVolume = true;
+            }
+        } else {
+            if ((newStreamDevice & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
+                // Restore speaker volume if exists. As there is no way to mute a device here,
+                // load system audio's volume and set it to speaker.
+                streamState.setIndex(oldIndex, AudioSystem.DEVICE_OUT_SPEAKER);
+                updateSpeakerVolume = true;
+            }
+        }
+
+        if (updateSpeakerVolume) {
+            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                    AudioSystem.DEVICE_OUT_SPEAKER, 0,
+                    streamState, 0);
+        }
+    }
 
     //==========================================================================================
     // Camera shutter sound policy.
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index e6e5dad..87468d6 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -287,6 +287,9 @@
                                                   DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
     public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY |
                                                   DEVICE_OUT_USB_DEVICE);
+    public static final int DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO = (DEVICE_OUT_LINE |
+                                                                DEVICE_OUT_HDMI_ARC |
+                                                                DEVICE_OUT_SPDIF);
 
     // input devices
     public static final int DEVICE_IN_COMMUNICATION = DEVICE_BIT_IN | 0x1;
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 4dcdd19..277d41e 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -197,4 +197,6 @@
     boolean isStreamAffectedByRingerMode(int streamType);
 
     void disableSafeMediaVolume();
+
+    oneway void setHdmiSystemAudioSupported(boolean on, int device, String name);
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 4458a8d..c668f5a 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -62,6 +62,7 @@
 import android.os.UserHandle;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.service.dreams.DreamManagerInternal;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.telecomm.TelecommManager;
@@ -224,6 +225,7 @@
     WindowManagerFuncs mWindowManagerFuncs;
     WindowManagerInternal mWindowManagerInternal;
     PowerManager mPowerManager;
+    DreamManagerInternal mDreamManagerInternal;
     IStatusBarService mStatusBarService;
     boolean mPreloadedRecentApps;
     final Object mServiceAquireLock = new Object();
@@ -934,6 +936,7 @@
         mWindowManager = windowManager;
         mWindowManagerFuncs = windowManagerFuncs;
         mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+        mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
 
         mHandler = new PolicyHandler();
         mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
@@ -1642,6 +1645,7 @@
         return windowTypeToLayerLw(TYPE_SYSTEM_ERROR);
     }
 
+    @Override
     public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) {
         if (mHasNavigationBar) {
             // For a basic navigation bar, when we are in landscape mode we place
@@ -1653,6 +1657,7 @@
         return fullWidth;
     }
 
+    @Override
     public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) {
         if (mHasNavigationBar) {
             // For a basic navigation bar, when we are in portrait mode we place
@@ -1664,10 +1669,12 @@
         return fullHeight;
     }
 
+    @Override
     public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation) {
         return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation);
     }
 
+    @Override
     public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) {
         // There is a separate status bar at the top of the display.  We don't count that as part
         // of the fixed decor, since it can hide; however, for purposes of configurations,
@@ -1823,6 +1830,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void removeStartingWindow(IBinder appToken, View window) {
         if (DEBUG_STARTING_WINDOW) {
             RuntimeException e = new RuntimeException("here");
@@ -1851,6 +1859,7 @@
      * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons,
      * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
      */
+    @Override
     public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
         switch (attrs.type) {
             case TYPE_STATUS_BAR:
@@ -1906,6 +1915,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void removeWindowLw(WindowState win) {
         if (mStatusBar == win) {
             mStatusBar = null;
@@ -2145,6 +2155,13 @@
                     return -1;
                 }
 
+                // If there's a dream running then use home to escape the dream
+                // but don't actually go home.
+                if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {
+                    mDreamManagerInternal.stopDream();
+                    return -1;
+                }
+
                 // Go home!
                 launchHomeFromHotKey();
                 return -1;
@@ -2635,6 +2652,7 @@
             // when in keyguard restricted mode, must first verify unlock
             // before launching home
             mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() {
+                @Override
                 public void onKeyguardExitResult(boolean success) {
                     if (success) {
                         try {
@@ -3903,6 +3921,7 @@
                 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
     }
 
+    @Override
     public boolean allowAppAnimationsLw() {
         if (isStatusBarKeyguard() || mShowingDream) {
             // If keyguard or dreams is currently visible, no reason to animate behind it.
@@ -3911,6 +3930,7 @@
         return true;
     }
 
+    @Override
     public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
         mFocusedWindow = newFocus;
         if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) {
@@ -3922,6 +3942,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
         // lid changed state
         final int newLidState = lidOpen ? LID_OPEN : LID_CLOSED;
@@ -4106,6 +4127,7 @@
         if (interactive || (isInjected && !isWakeKey)) {
             // When the screen is on or if the key is injected pass the key to the application.
             result = ACTION_PASS_TO_USER;
+            isWakeKey = false;
         } else {
             // When the screen is off and the key is not injected, determine whether
             // to wake the device but don't pass the key to the application.
@@ -4288,6 +4310,7 @@
 
             case KeyEvent.KEYCODE_WAKEUP: {
                 result &= ~ACTION_PASS_TO_USER;
+                isWakeKey = true;
                 break;
             }
 
@@ -4627,6 +4650,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void enableKeyguard(boolean enabled) {
         if (mKeyguardDelegate != null) {
             mKeyguardDelegate.setKeyguardEnabled(enabled);
@@ -4634,6 +4658,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
         if (mKeyguardDelegate != null) {
             mKeyguardDelegate.verifyUnlock(callback);
@@ -4647,11 +4672,13 @@
 
 
     /** {@inheritDoc} */
+    @Override
     public boolean isKeyguardLocked() {
         return keyguardOn();
     }
 
     /** {@inheritDoc} */
+    @Override
     public boolean isKeyguardSecure() {
         if (mKeyguardDelegate == null) return false;
         return mKeyguardDelegate.isSecure();
@@ -4663,14 +4690,17 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public boolean inKeyguardRestrictedKeyInputMode() {
         if (mKeyguardDelegate == null) return false;
         return mKeyguardDelegate.isInputRestricted();
     }
 
+    @Override
     public void dismissKeyguardLw() {
         if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
             mHandler.post(new Runnable() {
+                @Override
                 public void run() {
                     if (mKeyguardDelegate.isDismissable()) {
                         // Can we just finish the keyguard straight away?
@@ -4917,6 +4947,7 @@
         return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
     }
 
+    @Override
     public int getUserRotationMode() {
         return Settings.System.getIntForUser(mContext.getContentResolver(),
                 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ?
@@ -4925,6 +4956,7 @@
     }
 
     // User rotation: to be used when all else fails in assigning an orientation to the device
+    @Override
     public void setUserRotationMode(int mode, int rot) {
         ContentResolver res = mContext.getContentResolver();
 
@@ -4946,6 +4978,7 @@
         }
     }
 
+    @Override
     public void setSafeMode(boolean safeMode) {
         mSafeMode = safeMode;
         performHapticFeedbackLw(null, safeMode
@@ -4985,6 +5018,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void systemBooted() {
         if (mKeyguardDelegate != null) {
             mKeyguardDelegate.onBootCompleted();
@@ -4998,6 +5032,7 @@
     ProgressDialog mBootMsgDialog = null;
 
     /** {@inheritDoc} */
+    @Override
     public void showBootMessage(final CharSequence msg, final boolean always) {
         mHandler.post(new Runnable() {
             @Override public void run() {
@@ -5057,6 +5092,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void hideBootMessages() {
         mHandler.post(new Runnable() {
             @Override public void run() {
@@ -5069,6 +5105,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void userActivity() {
         // ***************************************
         // NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
@@ -5112,6 +5149,7 @@
 
     ScreenLockTimeout mScreenLockTimeout = new ScreenLockTimeout();
 
+    @Override
     public void lockNow(Bundle options) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
         mHandler.removeCallbacks(mScreenLockTimeout);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index c3284d4..a2df852 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -35,6 +35,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -754,6 +755,39 @@
         }
 
         @Override
+        public void setSystemAudioVolume(final int oldIndex, final int newIndex,
+                final int maxIndex) {
+            enforceAccessPermission();
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    HdmiCecLocalDeviceTv tv = tv();
+                    if (tv == null) {
+                        Slog.w(TAG, "Local tv device not available");
+                        return;
+                    }
+                    tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex);
+                }
+            });
+        }
+
+        @Override
+        public void setSystemAudioMute(final boolean mute) {
+            enforceAccessPermission();
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    HdmiCecLocalDeviceTv tv = tv();
+                    if (tv == null) {
+                        Slog.w(TAG, "Local tv device not available");
+                        return;
+                    }
+                    tv.changeMute(mute);
+                }
+            });
+        }
+
+        @Override
         public void setArcMode(final boolean enabled) {
             enforceAccessPermission();
             runOnServiceThread(new Runnable() {
@@ -761,7 +795,7 @@
                 public void run() {
                     HdmiCecLocalDeviceTv tv = tv();
                     if (tv == null) {
-                        Slog.w(TAG, "Local tv device not available to change arc mode.");
+                        Log.w(TAG, "Local tv device not available to change arc mode.");
                         return;
                     }
                 }