Merge "Reject request when any unknown flag is speficied" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 6fbd40b..686d6ab 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -905,6 +905,8 @@
     field public static final int multiprocess = 16842771; // 0x1010013
     field public static final int name = 16842755; // 0x1010003
     field public static final int navigationBarColor = 16843858; // 0x1010452
+    field public static final int navigationContentDescription = 16843970; // 0x10104c2
+    field public static final int navigationIcon = 16843969; // 0x10104c1
     field public static final int navigationMode = 16843471; // 0x10102cf
     field public static final int negativeButtonText = 16843254; // 0x10101f6
     field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
@@ -27196,16 +27198,14 @@
 package android.service.voice {
 
   public class AlwaysOnHotwordDetector {
-    method public android.content.Intent getManageIntent(int);
+    method public android.content.Intent createIntentToEnroll();
+    method public android.content.Intent createIntentToReEnroll();
+    method public android.content.Intent createIntentToUnEnroll();
     method public int getSupportedRecognitionModes();
     method public boolean startRecognition(int);
     method public boolean stopRecognition();
-    field public static final int MANAGE_ACTION_ENROLL = 0; // 0x0
-    field public static final int MANAGE_ACTION_RE_ENROLL = 1; // 0x1
-    field public static final int MANAGE_ACTION_UN_ENROLL = 2; // 0x2
     field public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 2; // 0x2
     field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1
-    field public static final int RECOGNITION_FLAG_NONE = 0; // 0x0
     field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2
     field public static final int RECOGNITION_MODE_VOICE_TRIGGER = 1; // 0x1
     field public static final int STATE_HARDWARE_UNAVAILABLE = -2; // 0xfffffffe
@@ -27214,7 +27214,8 @@
     field public static final int STATE_KEYPHRASE_UNSUPPORTED = -1; // 0xffffffff
   }
 
-  public static abstract interface AlwaysOnHotwordDetector.Callback {
+  public static abstract class AlwaysOnHotwordDetector.Callback {
+    ctor public AlwaysOnHotwordDetector.Callback();
     method public abstract void onAvailabilityChanged(int);
     method public abstract void onDetected(android.service.voice.AlwaysOnHotwordDetector.EventPayload);
     method public abstract void onError();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index c928a18..44e24b1 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -623,7 +623,7 @@
             try {
                 final ParcelFileDescriptor clientSocket = mSession.openWrite(name,
                         offsetBytes, lengthBytes);
-                return new FileBridge.FileBridgeOutputStream(clientSocket.getFileDescriptor());
+                return new FileBridge.FileBridgeOutputStream(clientSocket);
             } catch (RuntimeException e) {
                 ExceptionUtils.maybeUnwrapIOException(e);
                 throw e;
diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.java b/core/java/android/hardware/hdmi/HdmiPortInfo.java
index 85e7531..2ec6126 100644
--- a/core/java/android/hardware/hdmi/HdmiPortInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.java
@@ -166,7 +166,7 @@
     public String toString() {
         StringBuffer s = new StringBuffer();
         s.append("port_id: ").append(mId).append(", ");
-        s.append("address: ").append(mAddress).append(", ");
+        s.append("address: ").append(String.format("0x%04x", mAddress)).append(", ");
         s.append("cec: ").append(mCecSupported).append(", ");
         s.append("arc: ").append(mArcSupported).append(", ");
         s.append("mhl: ").append(mMhlSupported);
diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java
index bf8d15c..022a106 100644
--- a/core/java/android/os/FileBridge.java
+++ b/core/java/android/os/FileBridge.java
@@ -131,10 +131,17 @@
     }
 
     public static class FileBridgeOutputStream extends OutputStream {
+        private final ParcelFileDescriptor mClientPfd;
         private final FileDescriptor mClient;
         private final byte[] mTemp = new byte[MSG_LENGTH];
 
+        public FileBridgeOutputStream(ParcelFileDescriptor clientPfd) {
+            mClientPfd = clientPfd;
+            mClient = clientPfd.getFileDescriptor();
+        }
+
         public FileBridgeOutputStream(FileDescriptor client) {
+            mClientPfd = null;
             mClient = client;
         }
 
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 2095773..519bc28 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Activity;
 import android.content.Intent;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
@@ -84,20 +85,31 @@
     private static final int STATE_NOT_READY = 0;
 
     // Keyphrase management actions. Used in getManageIntent() ----//
-    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
                 MANAGE_ACTION_ENROLL,
                 MANAGE_ACTION_RE_ENROLL,
                 MANAGE_ACTION_UN_ENROLL
             })
-    public @interface ManageActions {}
+    private @interface ManageActions {}
 
-    /** Indicates that we need to enroll. */
+    /**
+     * Indicates that we need to enroll.
+     *
+     * @hide
+     */
     public static final int MANAGE_ACTION_ENROLL = 0;
-    /** Indicates that we need to re-enroll. */
+    /**
+     * Indicates that we need to re-enroll.
+     *
+     * @hide
+     */
     public static final int MANAGE_ACTION_RE_ENROLL = 1;
-    /** Indicates that we need to un-enroll. */
+    /**
+     * Indicates that we need to un-enroll.
+     *
+     * @hide
+     */
     public static final int MANAGE_ACTION_UN_ENROLL = 2;
 
     //-- Flags for startRecognition    ----//
@@ -111,7 +123,11 @@
             })
     public @interface RecognitionFlags {}
 
-    /** Empty flag for {@link #startRecognition(int)}. */
+    /**
+     * Empty flag for {@link #startRecognition(int)}.
+     *
+     * @hide
+     */
     public static final int RECOGNITION_FLAG_NONE = 0;
     /**
      * Recognition flag for {@link #startRecognition(int)} that indicates
@@ -264,7 +280,7 @@
     /**
      * Callbacks for always-on hotword detection.
      */
-    public interface Callback {
+    public static abstract class Callback {
         /**
          * Called when the hotword availability changes.
          * This indicates a change in the availability of recognition for the given keyphrase.
@@ -278,7 +294,7 @@
          * @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_UNENROLLED
          * @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_ENROLLED
          */
-        void onAvailabilityChanged(int status);
+        public abstract void onAvailabilityChanged(int status);
         /**
          * Called when the keyphrase is spoken.
          * This implicitly stops listening for the keyphrase once it's detected.
@@ -289,23 +305,23 @@
          *        This may contain the trigger audio, if requested when calling
          *        {@link AlwaysOnHotwordDetector#startRecognition(int)}.
          */
-        void onDetected(@NonNull EventPayload eventPayload);
+        public abstract void onDetected(@NonNull EventPayload eventPayload);
         /**
          * Called when the detection fails due to an error.
          */
-        void onError();
+        public abstract void onError();
         /**
          * Called when the recognition is paused temporarily for some reason.
          * This is an informational callback, and the clients shouldn't be doing anything here
          * except showing an indication on their UI if they have to.
          */
-        void onRecognitionPaused();
+        public abstract void onRecognitionPaused();
         /**
          * Called when the recognition is resumed after it was temporarily paused.
          * This is an informational callback, and the clients shouldn't be doing anything here
          * except showing an indication on their UI if they have to.
          */
-        void onRecognitionResumed();
+        public abstract void onRecognitionResumed();
     }
 
     /**
@@ -372,10 +388,10 @@
     /**
      * Starts recognition for the associated keyphrase.
      *
+     * @see #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
+     * @see #RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
+     *
      * @param recognitionFlags The flags to control the recognition properties.
-     *        The allowed flags are {@link #RECOGNITION_FLAG_NONE},
-     *        {@link #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO} and
-     *        {@link #RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS}.
      * @return Indicates whether the call succeeded or not.
      * @throws UnsupportedOperationException if the recognition isn't supported.
      *         Callers should only call this method after a supported state callback on
@@ -430,12 +446,13 @@
     }
 
     /**
-     * Gets an intent to manage the associated keyphrase.
+     * Creates an intent to start the enrollment for the associated keyphrase.
+     * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
+     * Starting re-enrollment is only valid if the keyphrase is un-enrolled,
+     * i.e. {@link #STATE_KEYPHRASE_UNENROLLED},
+     * otherwise {@link #createIntentToReEnroll()} should be preferred.
      *
-     * @param action The manage action that needs to be performed.
-     *        One of {@link #MANAGE_ACTION_ENROLL}, {@link #MANAGE_ACTION_RE_ENROLL} or
-     *        {@link #MANAGE_ACTION_UN_ENROLL}.
-     * @return An {@link Intent} to manage the given keyphrase.
+     * @return An {@link Intent} to start enrollment for the given keyphrase.
      * @throws UnsupportedOperationException if managing they keyphrase isn't supported.
      *         Callers should only call this method after a supported state callback on
      *         {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
@@ -443,10 +460,52 @@
      *         This may happen if another detector has been instantiated or the
      *         {@link VoiceInteractionService} hosting this detector has been shut down.
      */
-    public Intent getManageIntent(@ManageActions int action) {
-        if (DBG) Slog.d(TAG, "getManageIntent(" + action + ")");
+    public Intent createIntentToEnroll() {
+        if (DBG) Slog.d(TAG, "createIntentToEnroll");
         synchronized (mLock) {
-            return getManageIntentLocked(action);
+            return getManageIntentLocked(MANAGE_ACTION_ENROLL);
+        }
+    }
+
+    /**
+     * Creates an intent to start the un-enrollment for the associated keyphrase.
+     * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
+     * Starting re-enrollment is only valid if the keyphrase is already enrolled,
+     * i.e. {@link #STATE_KEYPHRASE_ENROLLED}, otherwise invoking this may result in an error.
+     *
+     * @return An {@link Intent} to start un-enrollment for the given keyphrase.
+     * @throws UnsupportedOperationException if managing they keyphrase isn't supported.
+     *         Callers should only call this method after a supported state callback on
+     *         {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+     * @throws IllegalStateException if the detector is in an invalid state.
+     *         This may happen if another detector has been instantiated or the
+     *         {@link VoiceInteractionService} hosting this detector has been shut down.
+     */
+    public Intent createIntentToUnEnroll() {
+        if (DBG) Slog.d(TAG, "createIntentToUnEnroll");
+        synchronized (mLock) {
+            return getManageIntentLocked(MANAGE_ACTION_UN_ENROLL);
+        }
+    }
+
+    /**
+     * Creates an intent to start the re-enrollment for the associated keyphrase.
+     * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
+     * Starting re-enrollment is only valid if the keyphrase is already enrolled,
+     * i.e. {@link #STATE_KEYPHRASE_ENROLLED}, otherwise invoking this may result in an error.
+     *
+     * @return An {@link Intent} to start re-enrollment for the given keyphrase.
+     * @throws UnsupportedOperationException if managing they keyphrase isn't supported.
+     *         Callers should only call this method after a supported state callback on
+     *         {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+     * @throws IllegalStateException if the detector is in an invalid state.
+     *         This may happen if another detector has been instantiated or the
+     *         {@link VoiceInteractionService} hosting this detector has been shut down.
+     */
+    public Intent createIntentToReEnroll() {
+        if (DBG) Slog.d(TAG, "createIntentToReEnroll");
+        synchronized (mLock) {
+            return getManageIntentLocked(MANAGE_ACTION_RE_ENROLL);
         }
     }
 
@@ -462,12 +521,6 @@
                     "Managing the given keyphrase is not supported");
         }
 
-        if (action != MANAGE_ACTION_ENROLL
-                && action != MANAGE_ACTION_RE_ENROLL
-                && action != MANAGE_ACTION_UN_ENROLL) {
-            throw new IllegalArgumentException("Invalid action specified " + action);
-        }
-
         return mKeyphraseEnrollmentInfo.getManageKeyphraseIntent(action, mText, mLocale);
     }
 
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 818efaa..ece8aa4 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -244,6 +244,16 @@
         // Set the default context, since setPopupTheme() may be a no-op.
         mPopupContext = mContext;
         setPopupTheme(a.getResourceId(R.styleable.Toolbar_popupTheme, 0));
+
+        final Drawable navIcon = a.getDrawable(R.styleable.Toolbar_navigationIcon);
+        if (navIcon != null) {
+            setNavigationIcon(navIcon);
+            final CharSequence navDesc = a.getText(
+                    R.styleable.Toolbar_navigationContentDescription);
+            if (!TextUtils.isEmpty(navDesc)) {
+                setNavigationContentDescription(navDesc);
+            }
+        }
         a.recycle();
     }
 
@@ -669,6 +679,8 @@
      * as screen readers or tooltips.
      *
      * @return The navigation button's content description
+     *
+     * @attr ref android.R.styleable#Toolbar_navigationContentDescription
      */
     @Nullable
     public CharSequence getNavigationContentDescription() {
@@ -682,6 +694,8 @@
      *
      * @param resId Resource ID of a content description string to set, or 0 to
      *              clear the description
+     *
+     * @attr ref android.R.styleable#Toolbar_navigationContentDescription
      */
     public void setNavigationContentDescription(int resId) {
         setNavigationContentDescription(resId != 0 ? getContext().getText(resId) : null);
@@ -694,6 +708,8 @@
      *
      * @param description Content description to set, or <code>null</code> to
      *                    clear the content description
+     *
+     * @attr ref android.R.styleable#Toolbar_navigationContentDescription
      */
     public void setNavigationContentDescription(@Nullable CharSequence description) {
         if (!TextUtils.isEmpty(description)) {
@@ -715,6 +731,8 @@
      * tooltips.</p>
      *
      * @param resId Resource ID of a drawable to set
+     *
+     * @attr ref android.R.styleable#Toolbar_navigationIcon
      */
     public void setNavigationIcon(int resId) {
         setNavigationIcon(getContext().getDrawable(resId));
@@ -731,6 +749,8 @@
      * tooltips.</p>
      *
      * @param icon Drawable to set, may be null to clear the icon
+     *
+     * @attr ref android.R.styleable#Toolbar_navigationIcon
      */
     public void setNavigationIcon(@Nullable Drawable icon) {
         if (icon != null) {
@@ -751,6 +771,8 @@
      * Return the current drawable used as the navigation icon.
      *
      * @return The navigation icon drawable
+     *
+     * @attr ref android.R.styleable#Toolbar_navigationIcon
      */
     @Nullable
     public Drawable getNavigationIcon() {
@@ -1316,6 +1338,8 @@
             final View bottomChild = layoutSubtitle ? mSubtitleTextView : mTitleTextView;
             final LayoutParams toplp = (LayoutParams) topChild.getLayoutParams();
             final LayoutParams bottomlp = (LayoutParams) bottomChild.getLayoutParams();
+            final boolean titleHasWidth = layoutTitle && mTitleTextView.getMeasuredWidth() > 0
+                    || layoutSubtitle && mSubtitleTextView.getMeasuredWidth() > 0;
 
             switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
                 case Gravity.TOP:
@@ -1343,7 +1367,7 @@
                     break;
             }
             if (isRtl) {
-                final int rd = mTitleMarginStart - collapsingMargins[1];
+                final int rd = (titleHasWidth ? mTitleMarginStart : 0) - collapsingMargins[1];
                 right -= Math.max(0, rd);
                 collapsingMargins[1] = Math.max(0, -rd);
                 int titleRight = right;
@@ -1366,9 +1390,11 @@
                     subtitleRight = subtitleRight - mTitleMarginEnd;
                     titleTop = subtitleBottom + lp.bottomMargin;
                 }
-                right = Math.min(titleRight, subtitleRight);
+                if (titleHasWidth) {
+                    right = Math.min(titleRight, subtitleRight);
+                }
             } else {
-                final int ld = mTitleMarginStart - collapsingMargins[0];
+                final int ld = (titleHasWidth ? mTitleMarginStart : 0) - collapsingMargins[0];
                 left += Math.max(0, ld);
                 collapsingMargins[0] = Math.max(0, -ld);
                 int titleLeft = left;
@@ -1391,7 +1417,9 @@
                     subtitleLeft = subtitleRight + mTitleMarginEnd;
                     titleTop = subtitleBottom + lp.bottomMargin;
                 }
-                left = Math.max(titleLeft, subtitleLeft);
+                if (titleHasWidth) {
+                    left = Math.max(titleLeft, subtitleLeft);
+                }
             }
         }
 
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9da116a..a798d2e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7318,6 +7318,12 @@
         <!-- Reference to a theme that should be used to inflate popups
              shown by widgets in the toolbar. -->
         <attr name="popupTheme" format="reference" />
+        <!-- Icon drawable to use for the navigation button located at
+             the start of the toolbar. -->
+        <attr name="navigationIcon" format="reference" />
+        <!-- Text to set as the content description for the navigation button
+             located at the start of the toolbar. -->
+        <attr name="navigationContentDescription" format="string" />
     </declare-styleable>
 
     <declare-styleable name="Toolbar_LayoutParams">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 3b49bed..d452739 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2280,6 +2280,8 @@
   <public type="attr" name="reparentWithOverlay" />
   <public type="attr" name="ambientShadowAlpha" />
   <public type="attr" name="spotShadowAlpha" />
+  <public type="attr" name="navigationIcon" />
+  <public type="attr" name="navigationContentDescription" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 90879dd..690b1d6 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2939,7 +2939,7 @@
             for (size_t i = 0; i < bags->size(); i++) {
                 TABLE_NOISY(printf("type=%d\n", i));
                 const TypeList& typeList = types[i];
-                if (typeList.isEmpty()) {
+                if (!typeList.isEmpty()) {
                     bag_set** typeBags = bags->get(i);
                     TABLE_NOISY(printf("typeBags=%p\n", typeBags));
                     if (typeBags) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 827b3ed..bb22b4d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -23,6 +23,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Predicate;
 import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
@@ -30,6 +31,8 @@
 
 import libcore.util.EmptyArray;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -446,7 +449,7 @@
                         allocated.add(address);
                     }
                 }
-                mIoThreadLogger.debug("DevicePollingResult:" + allocated);
+                mIoThreadLogger.debug("[P]:Allocated Address=" + allocated);
                 if (callback != null) {
                     runOnServiceThread(new Runnable() {
                         @Override
@@ -548,7 +551,7 @@
         runOnIoThread(new Runnable() {
             @Override
             public void run() {
-                mIoThreadLogger.debug("SendCommand:" + cecMessage);
+                mIoThreadLogger.debug("[S]:" + cecMessage);
                 byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
                 int i = 0;
                 int errorCode = Constants.SEND_RESULT_SUCCESS;
@@ -583,7 +586,7 @@
     private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) {
         assertRunOnServiceThread();
         HdmiCecMessage command = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body);
-        mServiceThreadLogger.debug("ReceiveCommand:" + command);
+        mServiceThreadLogger.debug("[R]:" + command);
         onReceiveCommand(command);
     }
 
@@ -598,6 +601,15 @@
         mService.onHotplug(port, connected);
     }
 
+    void dump(final IndentingPrintWriter pw) {
+        for (int i = 0; i < mLocalDevices.size(); ++i) {
+            pw.println("HdmiCecLocalDevice #" + i + ":");
+            pw.increaseIndent();
+            mLocalDevices.valueAt(i).dump(pw);
+            pw.decreaseIndent();
+        }
+    }
+
     private static native long nativeInit(HdmiCecController handler, MessageQueue messageQueue);
     private static native int nativeSendCecCommand(long controllerPtr, int srcAddress,
             int dstAddress, byte[] body);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
index 26d2cde..85f5be2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
@@ -43,6 +43,9 @@
  */
 abstract class HdmiCecFeatureAction {
     private static final String TAG = "HdmiCecFeatureAction";
+    // As all actions run in the same thread (service thread), it's fine to have single logger.
+    // TODO: create global logger for each threads and use them.
+    protected static final HdmiLogger DLOGGER = new HdmiLogger(TAG);
 
     // Timer handler message used for timeout event
     protected static final int MSG_TIMEOUT = 100;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index a12e4fc..38addba 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -28,6 +28,7 @@
 import android.view.KeyEvent;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 
 import java.util.ArrayList;
@@ -97,6 +98,17 @@
         public int hashCode() {
             return logicalAddress * 29 + physicalAddress;
         }
+        @Override
+        public String toString() {
+            StringBuffer s = new StringBuffer();
+            String logicalAddressString = (logicalAddress == Constants.ADDR_INVALID)
+                    ? "invalid" : String.format("0x%02x", logicalAddress);
+            s.append("logical_address: ").append(logicalAddressString);
+            String physicalAddressString = (physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS)
+                    ? "invalid" : String.format("0x%04x", physicalAddress);
+            s.append(", physical_address: ").append(physicalAddressString);
+            return s.toString();
+        }
     }
     // Logical address of the active source.
     @GuardedBy("mLock")
@@ -793,4 +805,16 @@
     protected void sendKeyEvent(int keyCode, boolean isPressed) {
         Slog.w(TAG, "sendKeyEvent not implemented");
     }
+
+    /**
+     * Dump internal status of HdmiCecLocalDevice object.
+     */
+    protected void dump(final IndentingPrintWriter pw) {
+        pw.println("mDeviceType: " + mDeviceType);
+        pw.println("mAddress: " + mAddress);
+        pw.println("mPreferredAddress: " + mPreferredAddress);
+        pw.println("mDeviceInfo: " + mDeviceInfo);
+        pw.println("mActiveSource: " + mActiveSource);
+        pw.println(String.format("mActiveRoutingPath: 0x%04x", mActiveRoutingPath));
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 5a2fa9c..6603a71 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -23,6 +23,7 @@
 import android.os.SystemProperties;
 import android.util.Slog;
 
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 
 /**
@@ -219,4 +220,10 @@
         mIsActiveSource = false;
         checkIfPendingActionsCleared();
     }
+
+    @Override
+    protected void dump(final IndentingPrintWriter pw) {
+        super.dump(pw);
+        pw.println("mIsActiveSource: " + mIsActiveSource);
+    }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index cd56cfc..1ab8069 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -45,6 +45,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
@@ -1610,4 +1611,16 @@
 
         invokeDeviceEventListener(newInfo, HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE);
     }
+
+    @Override
+    protected void dump(final IndentingPrintWriter pw) {
+        super.dump(pw);
+        pw.println("mArcEstablished: " + mArcEstablished);
+        pw.println("mArcFeatureEnabled: " + mArcFeatureEnabled);
+        pw.println("mSystemAudioActivated: " + mSystemAudioActivated);
+        pw.println("mSystemAudioMute: " + mSystemAudioMute);
+        pw.println("mAutoDeviceOff: " + mAutoDeviceOff);
+        pw.println("mAutoWakeup: " + mAutoWakeup);
+        pw.println("mSkipRoutingControl: " + mSkipRoutingControl);
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index e7b920a..d13e1de 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -67,6 +67,7 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.SystemService;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
@@ -75,6 +76,8 @@
 
 import libcore.util.EmptyArray;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -1395,6 +1398,28 @@
             enforceAccessPermission();
             HdmiControlService.this.addHdmiMhlScratchpadCommandListener(listener);
         }
+
+        @Override
+        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+
+            pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled);
+            pw.println("mProhibitMode: " + mProhibitMode);
+            if (mCecController != null) {
+                pw.println("mCecController: ");
+                pw.increaseIndent();
+                mCecController.dump(pw);
+                pw.decreaseIndent();
+            }
+            pw.println("mPortInfo: ");
+            pw.increaseIndent();
+            for (HdmiPortInfo hdmiPortInfo : mPortInfo) {
+                pw.println("- " + hdmiPortInfo);
+            }
+            pw.decreaseIndent();
+            pw.println("mPowerStatus: " + mPowerStatus);
+        }
     }
 
     @ServiceThreadOnly
diff --git a/services/core/java/com/android/server/hdmi/HdmiLogger.java b/services/core/java/com/android/server/hdmi/HdmiLogger.java
index ee9379d..c7add75 100644
--- a/services/core/java/com/android/server/hdmi/HdmiLogger.java
+++ b/services/core/java/com/android/server/hdmi/HdmiLogger.java
@@ -42,7 +42,7 @@
     private final String mTag;
 
     HdmiLogger(String tag) {
-        mTag = tag;
+        mTag = "HDMI:" + tag;
     }
 
     void warning(String logMessage) {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index ac2c7b9..d15ffb0 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -73,9 +73,9 @@
 
     // Seq #27
     protected void sendSystemAudioModeRequest() {
-        mState = STATE_CHECK_ROUTING_IN_PRGRESS;
         List<RoutingControlAction> routingActions = getActions(RoutingControlAction.class);
         if (!routingActions.isEmpty()) {
+            mState = STATE_CHECK_ROUTING_IN_PRGRESS;
             // Should have only one Routing Control Action
             RoutingControlAction routingAction = routingActions.get(0);
             routingAction.addOnFinishedCallback(this, new Runnable() {
@@ -97,20 +97,21 @@
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error == Constants.SEND_RESULT_SUCCESS) {
-                    mState = STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE;
-                    addTimer(mState, mTargetAudioStatus ? ON_TIMEOUT_MS : OFF_TIMEOUT_MS);
-                } else {
+                if (error != Constants.SEND_RESULT_SUCCESS) {
+                    DLOGGER.debug("Failed to send <System Audio Mode Request>:" + error);
                     setSystemAudioMode(false);
                     finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
                 }
             }
         });
+        mState = STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE;
+        addTimer(mState, mTargetAudioStatus ? ON_TIMEOUT_MS : OFF_TIMEOUT_MS);
     }
 
     private void handleSendSystemAudioModeRequestTimeout() {
         if (!mTargetAudioStatus  // Don't retry for Off case.
                 || mSendRetryCount++ >= MAX_SEND_RETRY_COUNT) {
+            DLOGGER.debug("[T]:wait for <Set System Audio Mode>.");
             setSystemAudioMode(false);
             finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
             return;
@@ -129,6 +130,7 @@
                 if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT
                         && (cmd.getParams()[0] & 0xFF)
                                 == Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST) {
+                    DLOGGER.debug("Failed to start system audio mode request.");
                     setSystemAudioMode(false);
                     finishWithCallback(HdmiControlManager.RESULT_EXCEPTION);
                     return true;
@@ -143,6 +145,7 @@
                     startAudioStatusAction();
                     return true;
                 } else {
+                    DLOGGER.debug("Unexpected system audio mode request:" + receivedStatus);
                     // Unexpected response, consider the request is newly initiated by AVR.
                     // To return 'false' will initiate new SystemAudioActionFromAvr by the control
                     // service.
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index e1a579c..1f01461 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -92,8 +92,7 @@
                 break;
             case AlwaysOnHotwordDetector.STATE_KEYPHRASE_UNENROLLED:
                 Log.i(TAG, "STATE_KEYPHRASE_UNENROLLED");
-                Intent enroll = mHotwordDetector.getManageIntent(
-                        AlwaysOnHotwordDetector.MANAGE_ACTION_ENROLL);
+                Intent enroll = mHotwordDetector.createIntentToEnroll();
                 Log.i(TAG, "Need to enroll with " + enroll);
                 break;
             case AlwaysOnHotwordDetector.STATE_KEYPHRASE_ENROLLED: