Merge "Fix shared library bug in bag attributes" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 8045c83..eb991ad 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27774,9 +27774,8 @@
   }
 
   public static class AlwaysOnHotwordDetector.EventPayload {
-    field public final android.media.AudioFormat audioFormat;
-    field public final byte[] data;
-    field public final boolean triggerAvailable;
+    method public android.media.AudioFormat getCaptureAudioFormat();
+    method public byte[] getTriggerAudio();
   }
 
   public class VoiceInteractionService extends android.app.Service {
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index 2e96487..0dbde6b 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -33,6 +33,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -263,4 +264,11 @@
         Slog.w(TAG, "Enrollment application doesn't support the given keyphrase/locale");
         return null;
     }
+
+    @Override
+    public String toString() {
+        return "KeyphraseEnrollmentInfo [Keyphrases=" + Arrays.toString(mKeyphrases)
+                + ", EnrollmentPackage=" + mEnrollmentPackage + ", ParseError=" + mParseError
+                + "]";
+    }
 }
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 47cfa7d..8db99a5 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -510,9 +510,10 @@
                 for (int i = 0; i < count; i++) {
                     final UserInfo user = users.get(i);
                     final UserHandle userHandle = user.getUserHandle();
-                    if (userManager.isUserRunning(userHandle) &&
-                            !userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
-                                    userHandle)) {
+                    if (userManager.isUserRunning(userHandle)
+                            && !userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
+                                    userHandle)
+                            && !user.isManagedProfile()) {
                         Uri uri = addEntryAndRemoveExpiredEntries(context,
                                 ContentProvider.maybeAddUserId(CONTENT_URI, user.id), values);
                         if (user.id == currentUserId) {
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index f1e1943..15e66a0 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -39,6 +39,8 @@
 
 import com.android.internal.app.IVoiceInteractionManagerService;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -185,48 +187,77 @@
      * Additional payload for {@link Callback#onDetected}.
      */
     public static class EventPayload {
-        /**
-         * Indicates if {@code data} is the audio that triggered the keyphrase.
-         */
-        public final boolean triggerAvailable;
-        /**
-         * Indicates if {@code captureSession} can be used to continue capturing more audio from
-         * the DSP hardware.
-         *
-         * Candidate for public API
-         * @hide
-         */
-        public final boolean captureAvailable;
-        /**
-         * The session to use when attempting to capture more audio from the DSP hardware.
-         *
-         * Candidate for public API
-         * TODO: When unhiding, change javadoc of audioFormat to -
-         * "Format of {@code data} or the audio that may be captured using {@code captureSession}.
-         * May be null if {@code triggerAvailable} and {@code captureAvailable} are false."
-         * @hide
-         */
-        public final int captureSession;
-        /**
-         * Format of {@code data}.
-         * May be null if {@code triggerAvailable} is false.
-         */
-        @Nullable
-        public final AudioFormat audioFormat;
-        /**
-         * Raw data associated with the event.
-         * This is the audio that triggered the keyphrase if {@code isTriggerAudio} is true.
-         */
-        @Nullable
-        public final byte[] data;
+        private final boolean mTriggerAvailable;
+        // Indicates if {@code captureSession} can be used to continue capturing more audio
+        // from the DSP hardware.
+        private final boolean mCaptureAvailable;
+        // The session to use when attempting to capture more audio from the DSP hardware.
+        private final int mCaptureSession;
+        private final AudioFormat mAudioFormat;
+        // Raw data associated with the event.
+        // This is the audio that triggered the keyphrase if {@code isTriggerAudio} is true.
+        private final byte[] mData;
 
-        private EventPayload(boolean _triggerAvailable, boolean _captureAvailable,
-                AudioFormat _audioFormat, int _captureSession, byte[] _data) {
-            triggerAvailable = _triggerAvailable;
-            captureAvailable = _captureAvailable;
-            captureSession = _captureSession;
-            audioFormat = _audioFormat;
-            data = _data;
+        private EventPayload(boolean triggerAvailable, boolean captureAvailable,
+                AudioFormat audioFormat, int captureSession, byte[] data) {
+            mTriggerAvailable = triggerAvailable;
+            mCaptureAvailable = captureAvailable;
+            mCaptureSession = captureSession;
+            mAudioFormat = audioFormat;
+            mData = data;
+        }
+
+        /**
+         * Gets the format of the audio obtained using {@link #getTriggerAudio()}.
+         * May be null if there's no audio present.
+         */
+        @Nullable
+        public AudioFormat getCaptureAudioFormat() {
+            return mAudioFormat;
+        }
+
+        /**
+         * Gets the raw audio that triggered the keyphrase.
+         * This may be null if the trigger audio isn't available.
+         * If non-null, the format of the audio can be obtained by calling
+         * {@link #getCaptureAudioFormat()}.
+         *
+         * @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
+         */
+        @Nullable
+        public byte[] getTriggerAudio() {
+            if (mTriggerAvailable) {
+                return mData;
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * Gets the session ID to start a capture from the DSP.
+         * This may be null if streaming capture isn't possible.
+         * If non-null, the format of the audio that can be captured can be
+         * obtained using {@link #getCaptureAudioFormat()}.
+         *
+         * TODO: Candidate for Public API when the API to start capture with a session ID
+         * is made public.
+         *
+         * TODO: Add this to {@link #getCaptureAudioFormat()}:
+         * "Gets the format of the audio obtained using {@link #getTriggerAudio()}
+         * or {@link #getCaptureSession()}. May be null if no audio can be obtained
+         * for either the trigger or a streaming session."
+         *
+         * TODO: Should this return a known invalid value instead?
+         *
+         * @hide
+         */
+        @Nullable
+        public Integer getCaptureSession() {
+            if (mCaptureAvailable) {
+                return mCaptureSession;
+            } else {
+                return null;
+            }
         }
     }
 
@@ -490,7 +521,7 @@
                     new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
                             recognitionExtra, null /* additional data */));
         } catch (RemoteException e) {
-            Slog.w(TAG, "RemoteException in startRecognition!");
+            Slog.w(TAG, "RemoteException in startRecognition!", e);
         }
         if (code != STATUS_OK) {
             Slog.w(TAG, "startRecognition() failed with error code " + code);
@@ -504,7 +535,7 @@
             code = mModelManagementService.stopRecognition(
                     mVoiceInteractionService, mKeyphraseMetadata.id, mInternalCallback);
         } catch (RemoteException e) {
-            Slog.w(TAG, "RemoteException in stopRecognition!");
+            Slog.w(TAG, "RemoteException in stopRecognition!", e);
         }
 
         if (code != STATUS_OK) {
@@ -636,7 +667,7 @@
                 dspModuleProperties =
                         mModelManagementService.getDspModuleProperties(mVoiceInteractionService);
             } catch (RemoteException e) {
-                Slog.w(TAG, "RemoteException in getDspProperties!");
+                Slog.w(TAG, "RemoteException in getDspProperties!", e);
             }
             // No DSP available
             if (dspModuleProperties == null) {
@@ -657,9 +688,20 @@
                 return mModelManagementService.isEnrolledForKeyphrase(
                         mVoiceInteractionService, keyphraseId);
             } catch (RemoteException e) {
-                Slog.w(TAG, "RemoteException in listRegisteredKeyphraseSoundModels!");
+                Slog.w(TAG, "RemoteException in listRegisteredKeyphraseSoundModels!", e);
             }
             return false;
         }
     }
+
+    /** @hide */
+    public void dump(String prefix, PrintWriter pw) {
+        synchronized (mLock) {
+            pw.print(prefix); pw.print("Text="); pw.println(mText);
+            pw.print(prefix); pw.print("Locale="); pw.println(mLocale);
+            pw.print(prefix); pw.print("Availability="); pw.println(mAvailability);
+            pw.print(prefix); pw.print("KeyphraseMetadata="); pw.println(mKeyphraseMetadata);
+            pw.print(prefix); pw.print("EnrollmentInfo="); pw.println(mKeyphraseEnrollmentInfo);
+        }
+    }
 }
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 5189404..770d66c 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -33,6 +33,9 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractionManagerService;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 
 /**
  * Top-level service of the current global voice interactor, which is providing
@@ -244,4 +247,17 @@
             // Ignore.
         }
     }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("VOICE INTERACTION");
+        synchronized (mLock) {
+            pw.println("  AlwaysOnHotwordDetector");
+            if (mHotwordDetector == null) {
+                pw.println("    NULL");
+            } else {
+                mHotwordDetector.dump("    ", pw);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index c3ea8f8..cd73527 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -83,7 +83,7 @@
     <color name="notification_material_background_dimmed_color">#d4ffffff</color>
 
     <!-- The color of the material notification background when low priority -->
-    <color name="notification_material_background_low_priority_color">#ffdcdcdc</color>
+    <color name="notification_material_background_low_priority_color">#ffe0e0e0</color>
 
     <!-- The color of the ripples on the untinted notifications -->
     <color name="notification_ripple_untinted_color">#20000000</color>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 1cd18a0..6ac0bef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -660,6 +660,7 @@
     }
 
     public void reset() {
+        super.reset();
         setTintColor(0);
         setShowingLegacyBackground(false);
         setBelowSpeedBump(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 0960c00..a275572 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -59,6 +59,7 @@
     private boolean mClearable;
     private ExpansionLogger mLogger;
     private String mLoggingKey;
+    private boolean mWasReset;
 
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
@@ -88,6 +89,7 @@
         mPublicLayout.reset();
         mPrivateLayout.reset();
         mMaxExpandHeight = 0;
+        mWasReset = true;
         logExpansionEvent(false, wasExpanded);
     }
 
@@ -246,11 +248,12 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        boolean updateExpandHeight = mMaxExpandHeight == 0;
+        boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
         mMaxExpandHeight = mPrivateLayout.getMaxHeight();
         if (updateExpandHeight) {
             applyExpansionToLayout();
         }
+        mWasReset = false;
     }
 
     public void setSensitive(boolean sensitive) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 46d4a9a..df64edf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -255,6 +255,10 @@
     public void setBelowSpeedBump(boolean below) {
     }
 
+    public void reset() {
+        mOnHeightChangedListener.onReset(this);
+    }
+
     /**
      * A listener notifying when {@link #getActualHeight} changes.
      */
@@ -265,5 +269,12 @@
          *             padding or the padding between the elements changed
          */
         void onHeightChanged(ExpandableView view);
+
+        /**
+         * Called when the view is reset and therefore the height will change abruptly
+         *
+         * @param view The view which was reset.
+         */
+        void onReset(ExpandableView view);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index a07bc5c..1d08658 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1469,6 +1469,10 @@
     }
 
     @Override
+    public void onReset(ExpandableView view) {
+    }
+
+    @Override
     public void onScrollChanged() {
         if (mQsExpanded) {
             requestScrollerTopPaddingUpdate(false /* animate */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index fec5e74..d2b97d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -163,6 +163,8 @@
     private int mNotificationTopPadding;
     private float mTopPaddingOverflow;
     private boolean mDontReportNextOverScroll;
+    private boolean mRequestViewResizeAnimationOnLayout;
+    private boolean mNeedViewResizeAnimation;
 
     /**
      * The maximum scrollPosition which we are allowed to reach when a notification was expanded.
@@ -319,9 +321,18 @@
         setMaxLayoutHeight(getHeight());
         updateContentHeight();
         clampScrollPosition();
+        requestAnimationOnViewResize();
         requestChildrenUpdate();
     }
 
+    private void requestAnimationOnViewResize() {
+        if (mRequestViewResizeAnimationOnLayout && mIsExpanded && mAnimationsEnabled) {
+            mNeedViewResizeAnimation = true;
+            mNeedsAnimation = true;
+        }
+        mRequestViewResizeAnimationOnLayout = false;
+    }
+
     public void updateSpeedBumpIndex(int newIndex) {
         int currentIndex = indexOfChild(mSpeedBumpView);
 
@@ -1598,9 +1609,18 @@
         generateHideSensitiveEvent();
         generateDarkEvent();
         generateGoToFullShadeEvent();
+        generateViewResizeEvent();
         mNeedsAnimation = false;
     }
 
+    private void generateViewResizeEvent() {
+        if (mNeedViewResizeAnimation) {
+            mAnimationEvents.add(
+                    new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_VIEW_RESIZE));
+        }
+        mNeedViewResizeAnimation = false;
+    }
+
     private void generateSnapBackEvents() {
         for (View child : mSnappedBackChildren) {
             mAnimationEvents.add(new AnimationEvent(child,
@@ -1892,6 +1912,11 @@
         requestChildrenUpdate();
     }
 
+    @Override
+    public void onReset(ExpandableView view) {
+        mRequestViewResizeAnimationOnLayout = true;
+    }
+
     private void updateScrollPositionOnExpandInBottom(ExpandableView view) {
         if (view instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) view;
@@ -2258,6 +2283,14 @@
                 // ANIMATION_TYPE_HIDE_SENSITIVE
                 new AnimationFilter()
                         .animateHideSensitive(),
+
+                // ANIMATION_TYPE_VIEW_RESIZE
+                new AnimationFilter()
+                        .animateAlpha()
+                        .animateHeight()
+                        .animateTopInset()
+                        .animateY()
+                        .animateZ(),
         };
 
         static int[] LENGTHS = new int[] {
@@ -2297,6 +2330,9 @@
 
                 // ANIMATION_TYPE_HIDE_SENSITIVE
                 StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_VIEW_RESIZE
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
         };
 
         static final int ANIMATION_TYPE_ADD = 0;
@@ -2311,6 +2347,7 @@
         static final int ANIMATION_TYPE_DARK = 9;
         static final int ANIMATION_TYPE_GO_TO_FULL_SHADE = 10;
         static final int ANIMATION_TYPE_HIDE_SENSITIVE = 11;
+        static final int ANIMATION_TYPE_VIEW_RESIZE = 12;
 
         final long eventStartTime;
         final View changingView;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
index 994f758..3a64984 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
@@ -159,7 +159,7 @@
                 try {
                     mActiveListener.onError(STATUS_ERROR);
                 } catch (RemoteException e) {
-                    Slog.w(TAG, "RemoteException in onDetectionStopped");
+                    Slog.w(TAG, "RemoteException in onDetectionStopped", e);
                 }
                 mActiveListener = null;
             }