Merge "Fixed flickering in panel overscroll" into lmp-preview-dev
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 98f70f40..a6cddae 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -33,6 +33,8 @@
  * A service that notifies the system about whether it believes the environment of the device
  * to be trusted.
  *
+ * <p>Trust agents may only be provided by the platform.</p>
+ *
  * <p>To extend this class, you must declare the service in your manifest file with
  * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
  * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 55f52da..1f1ee1c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2602,6 +2602,13 @@
                 android:label="@string/permlab_trust_listener"
                 android:description="@string/permdesc_trust_listener" />
 
+    <!-- Allows an application to provide a trust agent.
+         @hide For security reasons, this is a platform-only permission. -->
+    <permission android:name="android.permission.PROVIDE_TRUST_AGENT"
+                android:protectionLevel="signatureOrSystem"
+                android:label="@string/permlab_provide_trust_agent"
+                android:description="@string/permdesc_provide_trust_agent" />
+
     <!-- Must be required by an {@link
          android.service.trust.TrustAgentService},
          to ensure that only the system can bind to it. -->
diff --git a/core/res/res/transition/fade.xml b/core/res/res/transition/fade.xml
new file mode 100644
index 0000000..22397d4
--- /dev/null
+++ b/core/res/res/transition/fade.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<fade xmlns:android="http://schemas.android.com/apk/res/android"/>
diff --git a/core/res/res/transition/move.xml b/core/res/res/transition/move.xml
new file mode 100644
index 0000000..d4863ee
--- /dev/null
+++ b/core/res/res/transition/move.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+    <transitionSet>
+        <changeBounds/>
+        <changeTransform/>
+        <changeClipBounds/>
+        <targets>
+            <target android:excludeClass="android.widget.ImageView"/>
+        </targets>
+    </transitionSet>
+    <moveImage>
+        <targets>
+            <target android:targetClass="android.widget.ImageView"/>
+        </targets>
+    </moveImage>
+</transitionSet>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5d6987c..d4465e6 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3774,6 +3774,11 @@
     <!-- Description of an application permission that lets it listen to trust state changes. -->
     <string name="permdesc_trust_listener">Allows an application to listen for changes in trust state.</string>
 
+    <!-- Title of an application permission that lets it provide a trust agent. -->
+    <string name="permlab_provide_trust_agent">Provide a trust agent.</string>
+    <!-- Description of an application permission that lets it provide a trust agent. -->
+    <string name="permdesc_provide_trust_agent">Allows an application to provide a trust agent.</string>
+
     <!-- Title of an application permission that lets it bind to a trust agent service. -->
     <string name="permlab_bind_trust_agent_service">Bind to a trust agent service</string>
     <!-- Description of an application permission that lets it bind to a trust agent service. -->
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index f47ea7a..eda7174 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -165,6 +165,9 @@
         <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
         <item name="statusBarColor">?attr/colorPrimaryDark</item>
         <item name="navigationBarColor">@color/black</item>
+        <item name="windowEnterTransition">@transition/fade</item>
+        <item name="windowSharedElementEnterTransition">@transition/move</item>
+        <item name="windowSharedElementExitTransition">@transition/move</item>
 
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/Theme.Quantum.Dialog</item>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 8cf07fa..55d8d81 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -59,8 +59,8 @@
     <string name="keyguard_charged">Charged</string>
 
     <!-- When the lock screen is showing and the phone plugged in, and the battery
-         is not fully charged, show the current charge %.  -->
-    <string name="keyguard_plugged_in">Charging, <xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g></string>
+         is not fully charged, say that it's charging.  -->
+    <string name="keyguard_plugged_in">Charging</string>
 
     <!-- When the lock screen is showing and the battery is low, warn user to plug
          in the phone soon. -->
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index e6de72f..a0b5536 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -475,7 +475,8 @@
             interpolator, null);
 
             // And the forgot pattern button
-            if (mForgotPatternButton.getVisibility() == View.VISIBLE) {
+            if (mForgotPatternButton != null
+                    && mForgotPatternButton.getVisibility() == View.VISIBLE) {
                 mAppearAnimationUtils.createAnimation(mForgotPatternButton, delay, duration,
                         startTranslationY, interpolator, null);
             }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index fef971c..668e1ef 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -418,7 +418,7 @@
         }
     }
 
-    /* package */ static class BatteryStatus {
+    public static class BatteryStatus {
         public final int status;
         public final int level;
         public final int plugged;
diff --git a/packages/Keyguard/test/SampleTrustAgent/Android.mk b/packages/Keyguard/test/SampleTrustAgent/Android.mk
index 7551fdf..2a18ee1 100644
--- a/packages/Keyguard/test/SampleTrustAgent/Android.mk
+++ b/packages/Keyguard/test/SampleTrustAgent/Android.mk
@@ -20,9 +20,8 @@
 
 LOCAL_PACKAGE_NAME := SampleTrustAgent
 
-# Remove these to verify permission checks are working correctly
-#LOCAL_CERTIFICATE := platform
-#LOCAL_PRIVILEGED_MODULE := true
+# Remove this to verify permission checks are working correctly
+LOCAL_CERTIFICATE := platform
 
 LOCAL_MODULE_TAGS := tests
 
diff --git a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
index 7904927..f3125f1 100644
--- a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
+++ b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
@@ -18,6 +18,7 @@
     package="com.android.trustagent.test">
     <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17"/>
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
+    <uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT" />
     <application android:label="@string/app_name">
       <service
           android:name=".SampleTrustAgent"
diff --git a/packages/SystemUI/res/drawable/keyguard_overflow_number_background.xml b/packages/SystemUI/res/drawable/keyguard_overflow_number_background.xml
new file mode 100644
index 0000000..b812d43
--- /dev/null
+++ b/packages/SystemUI/res/drawable/keyguard_overflow_number_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#1a000000" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index f867068..c442f79 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -32,20 +32,20 @@
         />
     <TextView
         android:id="@+id/more_text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:layout_marginStart="20dp"
         android:layout_gravity="center_vertical"
-        android:gravity="center_horizontal"
-        android:textColor="@color/keyguard_overflow_content_color"
-        android:textAllCaps="true"
-        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:background="@drawable/keyguard_overflow_number_background"
+        android:gravity="center"
+        android:textColor="#ff686868"
+        android:textStyle="bold"
+        android:textSize="14dp"
         />
     <com.android.systemui.statusbar.NotificationOverflowIconsView
         android:id="@+id/overflow_icons_view"
-        android:layout_gravity="end|center_vertical"
-        android:gravity="end"
-        android:paddingLeft="8dp"
-        android:paddingRight="8dp"
+        android:layout_gravity="center_vertical"
+        android:layout_marginStart="68dp"
         android:layout_width="120dp"
         android:layout_height="wrap_content"
         />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 757d4ad..34cfbe8e 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -46,7 +46,7 @@
     <drawable name="notification_item_background_color_pressed">#ff454545</drawable>
 
     <!-- Tint color for the content on the notification overflow card. -->
-    <color name="keyguard_overflow_content_color">#ff666666</color>
+    <color name="keyguard_overflow_content_color">#ff686868</color>
 
     <!-- The color of the red speed bump dot -->
     <color name="speed_bump_dot_red">#ffd50000</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b6c04f7..35bc7e3 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -83,7 +83,7 @@
     <dimen name="notification_mid_height">128dp</dimen>
 
     <!-- Height of a the summary ("more card") notification on keyguard. -->
-    <dimen name="notification_summary_height">40dp</dimen>
+    <dimen name="notification_summary_height">44dp</dimen>
 
     <!-- size at which Notification icons will be drawn in the status bar -->
     <dimen name="status_bar_icon_drawing_size">18dip</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 79c7031..de297e5 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -558,10 +558,8 @@
     <!-- Zen mode: Short title. [CHAR LIMIT=40] -->
     <string name="zen_mode_title">Do not disturb</string>
 
-    <!-- Text for overflow card on Keyguard when there is not enough space for all notifications on Keyguard. [CHAR LIMIT=12] -->
-    <plurals name="keyguard_more_overflow_text">
-        <item quantity="other">%d more</item>
-    </plurals>
+    <!-- Text for overflow card on Keyguard when there is not enough space for all notifications on Keyguard. [CHAR LIMIT=1] -->
+    <string name="keyguard_more_overflow_text">+<xliff:g id="number_of_notifications" example="5">%d</xliff:g></string>
 
     <!-- An explanation for the visual speed bump in the notifications, which will appear when you click on it. [CHAR LIMIT=50] -->
     <string name="speed_bump_explanation">Less urgent notifications below</string>
@@ -583,6 +581,9 @@
     <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
     <string name="zen_mode_forever">Until you turn this off</string>
 
+    <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
+    <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
+
     <!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
     <plurals name="zen_mode_duration_minutes">
         <item quantity="one">For one minute</item>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 088f076..ac2537c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -69,7 +69,9 @@
                         ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
                         : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
                 }
-                child.measure(widthMeasureSpec, childHeightSpec);
+                child.measure(
+                        getChildMeasureSpec(widthMeasureSpec, 0 /* padding */, layoutParams.width),
+                        childHeightSpec);
                 int childHeight = child.getMeasuredHeight();
                 maxChildHeight = Math.max(maxChildHeight, childHeight);
             } else {
@@ -79,7 +81,9 @@
         int ownHeight = hasFixedHeight ? ownMaxHeight : maxChildHeight;
         newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
         for (View child : mMatchParentViews) {
-            child.measure(widthMeasureSpec, newHeightSpec);
+            child.measure(getChildMeasureSpec(
+                    widthMeasureSpec, 0 /* padding */, child.getLayoutParams().width),
+                    newHeightSpec);
         }
         mMatchParentViews.clear();
         int width = MeasureSpec.getSize(widthMeasureSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
new file mode 100644
index 0000000..ce35e4b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.text.format.Formatter;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * Controls the little text indicator on the keyguard.
+ */
+public class KeyguardIndicationController {
+
+    private static final String TAG = "KeyguardIndicationController";
+
+    private static final int MSG_HIDE_TRANSIENT = 1;
+
+    private final Context mContext;
+    private final KeyguardIndicationTextView mTextView;
+    private final IBatteryStats mBatteryInfo;
+
+    private String mRestingIndication;
+    private String mTransientIndication;
+    private boolean mVisible;
+
+    private boolean mPowerPluggedIn;
+    private boolean mPowerCharged;
+
+    public KeyguardIndicationController(Context context, KeyguardIndicationTextView textView) {
+        mContext = context;
+        mTextView = textView;
+
+        mBatteryInfo = IBatteryStats.Stub.asInterface(
+                ServiceManager.getService(BatteryStats.SERVICE_NAME));
+        KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitor);
+        context.registerReceiverAsUser(
+                mReceiver, UserHandle.OWNER, new IntentFilter(Intent.ACTION_TIME_TICK), null, null);
+    }
+
+    public void setVisible(boolean visible) {
+        mVisible = visible;
+        mTextView.setVisibility(visible ? View.VISIBLE : View.GONE);
+        if (visible) {
+            hideTransientIndication();
+            updateIndication();
+        }
+    }
+
+    /**
+     * Sets the indication that is shown if nothing else is showing.
+     */
+    public void setRestingIndication(String restingIndication) {
+        mRestingIndication = restingIndication;
+        updateIndication();
+    }
+
+    /**
+     * Hides transient indication in {@param delayMs}.
+     */
+    public void hideTransientIndicationDelayed(long delayMs) {
+        mHandler.sendMessageDelayed(
+                mHandler.obtainMessage(MSG_HIDE_TRANSIENT), delayMs);
+    }
+
+    /**
+     * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
+     */
+    public void showTransientIndication(int transientIndication) {
+        showTransientIndication(mContext.getResources().getString(transientIndication));
+    }
+
+    /**
+     * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
+     */
+    public void showTransientIndication(String transientIndication) {
+        mTransientIndication = transientIndication;
+        mHandler.removeMessages(MSG_HIDE_TRANSIENT);
+        updateIndication();
+    }
+
+    /**
+     * Hides transient indication.
+     */
+    public void hideTransientIndication() {
+        if (mTransientIndication != null) {
+            mTransientIndication = null;
+            mHandler.removeMessages(MSG_HIDE_TRANSIENT);
+            updateIndication();
+        }
+    }
+
+    private void updateIndication() {
+        if (mVisible) {
+            mTextView.switchIndication(computeIndication());
+        }
+    }
+
+    private String computeIndication() {
+        if (!TextUtils.isEmpty(mTransientIndication)) {
+            return mTransientIndication;
+        }
+        if (mPowerPluggedIn) {
+            return computePowerIndication();
+        }
+        return mRestingIndication;
+    }
+
+    private String computePowerIndication() {
+        if (mPowerCharged) {
+            return mContext.getResources().getString(R.string.keyguard_charged);
+        }
+
+        // Try fetching charging time from battery stats.
+        try {
+            long chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
+            if (chargingTimeRemaining > 0) {
+                String chargingTimeFormatted =
+                        Formatter.formatShortElapsedTime(mContext, chargingTimeRemaining);
+                return mContext.getResources().getString(
+                        R.string.keyguard_indication_charging_time, chargingTimeFormatted);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling IBatteryStats: ", e);
+        }
+
+        // Fall back to simple charging label.
+        return mContext.getResources().getString(R.string.keyguard_plugged_in);
+    }
+
+    KeyguardUpdateMonitorCallback mUpdateMonitor = new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
+            mPowerPluggedIn = status.status == BatteryManager.BATTERY_STATUS_CHARGING
+                    || status.status == BatteryManager.BATTERY_STATUS_FULL;
+            mPowerCharged = status.isCharged();
+            updateIndication();
+        }
+    };
+
+    BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (mVisible) {
+                updateIndication();
+            }
+        }
+    };
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == MSG_HIDE_TRANSIENT && mTransientIndication != null) {
+                mTransientIndication = null;
+                updateIndication();
+            }
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
index ce31894..6819d9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
@@ -18,15 +18,13 @@
 
 import android.app.Notification;
 import android.content.Context;
-import android.graphics.Color;
+import android.content.res.Configuration;
 import android.graphics.PorterDuff;
 import android.util.AttributeSet;
-import android.view.View;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.IconMerger;
 
@@ -37,6 +35,8 @@
 
     private TextView mMoreText;
     private int mTintColor;
+    private int mIconSize;
+    private NotificationColorUtil mNotificationColorUtil = new NotificationColorUtil();
 
     public NotificationOverflowIconsView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -46,6 +46,8 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mTintColor = getResources().getColor(R.color.keyguard_overflow_content_color);
+        mIconSize = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_icon_size);
     }
 
     public void setMoreText(TextView moreText) {
@@ -56,14 +58,24 @@
         StatusBarIconView v = new StatusBarIconView(getContext(), "",
                 notification.notification.getNotification());
         v.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-        v.setColorFilter(mTintColor, PorterDuff.Mode.MULTIPLY);
-        addView(v);
+        addView(v, mIconSize, mIconSize);
         v.set(notification.icon.getStatusBarIcon());
+        applyColor(notification.notification.getNotification(), v);
         updateMoreText();
     }
 
+    private void applyColor(Notification notification, StatusBarIconView view) {
+        if (notification.color != Notification.COLOR_DEFAULT) {
+            if (mNotificationColorUtil.isGrayscale(view.getDrawable())) {
+                view.setColorFilter(mTintColor, PorterDuff.Mode.MULTIPLY);
+            }
+        } else {
+            view.setColorFilter(notification.color, PorterDuff.Mode.SRC_ATOP);
+        }
+    }
+
     private void updateMoreText() {
-        mMoreText.setText(getResources().getQuantityString(
-                R.plurals.keyguard_more_overflow_text, getChildCount(), getChildCount()));
+        mMoreText.setText(
+                getResources().getString(R.string.keyguard_more_overflow_text, getChildCount()));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index e4133db..5442bc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -638,10 +638,12 @@
         if (mHintAnimationRunning) {
             return true;
         }
-        if (x < mEdgeTapAreaWidth) {
+        if (x < mEdgeTapAreaWidth
+                && mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
             onEdgeClicked(false /* right */);
             return true;
-        } else if (x > getWidth() - mEdgeTapAreaWidth) {
+        } else if (x > getWidth() - mEdgeTapAreaWidth
+                && mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
             onEdgeClicked(true /* right */);
             return true;
         } else {
@@ -655,7 +657,7 @@
                 startUnlockHintAnimation();
                 return true;
             case StatusBarState.SHADE_LOCKED:
-                // TODO: Go to Keyguard again.
+                mStatusBar.goToKeyguard();
                 return true;
             case StatusBarState.SHADE:
                 collapse();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 93b5ee5..e55de94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -105,6 +105,7 @@
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.InterceptedNotifications;
+import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.NotificationData.Entry;
 import com.android.systemui.statusbar.NotificationOverflowContainer;
@@ -122,7 +123,6 @@
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
 import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
 import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
@@ -253,10 +253,8 @@
     View mKeyguardStatusView;
     KeyguardBottomAreaView mKeyguardBottomArea;
     boolean mLeaveOpenOnKeyguardHide;
-    KeyguardIndicationTextView mKeyguardIndicationTextView;
+    KeyguardIndicationController mKeyguardIndicationController;
 
-    // TODO: Fetch phrase from search/hotword provider.
-    String mKeyguardHotwordPhrase = "";
     int mKeyguardMaxNotificationCount;
     View mDateTimeView;
 
@@ -496,13 +494,6 @@
         }
     };
 
-    private final Runnable mResetIndicationRunnable = new Runnable() {
-        @Override
-        public void run() {
-            mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
-        }
-    };
-
     @Override
     public void setZenMode(int mode) {
         super.setZenMode(mode);
@@ -674,8 +665,9 @@
         mKeyguardBottomArea =
                 (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
         mKeyguardBottomArea.setActivityStarter(this);
-        mKeyguardIndicationTextView = (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
-                R.id.keyguard_indication_text);
+        mKeyguardIndicationController = new KeyguardIndicationController(mContext,
+                (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
+                        R.id.keyguard_indication_text));
         mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
 
         mDateTimeView = mHeader.findViewById(R.id.datetime);
@@ -2866,12 +2858,11 @@
     private void updateKeyguardState() {
         if (mState == StatusBarState.KEYGUARD) {
             mKeyguardStatusView.setVisibility(View.VISIBLE);
-            mKeyguardIndicationTextView.setVisibility(View.VISIBLE);
-            mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+            mKeyguardIndicationController.setVisible(true);
             mNotificationPanel.resetViews();
         } else {
             mKeyguardStatusView.setVisibility(View.GONE);
-            mKeyguardIndicationTextView.setVisibility(View.GONE);
+            mKeyguardIndicationController.setVisible(false);
         }
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
             mKeyguardBottomArea.setVisibility(View.VISIBLE);
@@ -2958,7 +2949,7 @@
     @Override
     public void onActivated(View view) {
         userActivity();
-        mKeyguardIndicationTextView.switchIndication(R.string.notification_tap_again);
+        mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
         mStackScroller.setActivatedChild(view);
     }
 
@@ -2973,7 +2964,7 @@
     @Override
     public void onActivationReset(View view) {
         if (view == mStackScroller.getActivatedChild()) {
-            mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+            mKeyguardIndicationController.hideTransientIndication();
             mStackScroller.setActivatedChild(null);
         }
     }
@@ -2982,24 +2973,20 @@
     }
 
     public void onUnlockHintStarted() {
-        mStatusBarView.removeCallbacks(mResetIndicationRunnable);
-        mKeyguardIndicationTextView.switchIndication(R.string.keyguard_unlock);
+        mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
     }
 
     public void onHintFinished() {
-
         // Delay the reset a bit so the user can read the text.
-        mStatusBarView.postDelayed(mResetIndicationRunnable, HINT_RESET_DELAY_MS);
+        mKeyguardIndicationController.hideTransientIndicationDelayed(HINT_RESET_DELAY_MS);
     }
 
     public void onCameraHintStarted() {
-        mStatusBarView.removeCallbacks(mResetIndicationRunnable);
-        mKeyguardIndicationTextView.switchIndication(R.string.camera_hint);
+        mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
     }
 
     public void onPhoneHintStarted() {
-        mStatusBarView.removeCallbacks(mResetIndicationRunnable);
-        mKeyguardIndicationTextView.switchIndication(R.string.phone_hint);
+        mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
     }
 
     public void onTrackingStopped(boolean expand) {
@@ -3063,6 +3050,16 @@
     }
 
     /**
+     * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
+     */
+    public void goToKeyguard() {
+        if (mState == StatusBarState.SHADE_LOCKED) {
+            setBarState(StatusBarState.KEYGUARD);
+            updateKeyguardState();
+        }
+    }
+
+    /**
      * @return a ViewGroup that spans the entire panel which contains the quick settings
      */
     public ViewGroup getQuickSettingsOverlayParent() {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 986cdc1..462b234 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -49,6 +49,7 @@
 import android.service.trust.TrustAgentService;
 import android.util.ArraySet;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.Xml;
@@ -80,6 +81,7 @@
 
     private static final Intent TRUST_AGENT_INTENT =
             new Intent(TrustAgentService.SERVICE_INTERFACE);
+    private static final String PERMISSION_PROVIDE_AGENT = Manifest.permission.PROVIDE_TRUST_AGENT;
 
     private static final int MSG_REGISTER_LISTENER = 1;
     private static final int MSG_UNREGISTER_LISTENER = 2;
@@ -181,6 +183,15 @@
                     PackageManager.GET_META_DATA, userInfo.id);
             for (ResolveInfo resolveInfo : resolveInfos) {
                 if (resolveInfo.serviceInfo == null) continue;
+
+                String packageName = resolveInfo.serviceInfo.packageName;
+                if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    Log.w(TAG, "Skipping agent because package " + packageName
+                            + " does not have permission " + PERMISSION_PROVIDE_AGENT + ".");
+                    continue;
+                }
+
                 ComponentName name = getComponentName(resolveInfo);
                 if (!enabledAgents.contains(name)) continue;