Merge "Fix the Locale story in the hotword API" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 20c4db9..a592b0e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22465,21 +22465,21 @@
   }
 
   public final class PowerManager {
-    method public void goToSleep(long);
     method public boolean isInteractive();
     method public boolean isPowerSaveMode();
     method public deprecated boolean isScreenOn();
+    method public boolean isWakeLockLevelSupported(int);
     method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
     method public void reboot(java.lang.String);
-    method public void userActivity(long, boolean);
-    method public void wakeUp(long);
     field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
     field public static final java.lang.String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
     field public static final deprecated int FULL_WAKE_LOCK = 26; // 0x1a
     field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000
     field public static final int PARTIAL_WAKE_LOCK = 1; // 0x1
+    field public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32; // 0x20
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+    field public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1; // 0x1
   }
 
   public final class PowerManager.WakeLock {
@@ -22487,6 +22487,7 @@
     method public void acquire(long);
     method public boolean isHeld();
     method public void release();
+    method public void release(int);
     method public void setReferenceCounted(boolean);
     method public void setWorkSource(android.os.WorkSource);
   }
diff --git a/api/removed.txt b/api/removed.txt
index 465a18d..93484de 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -6,6 +6,16 @@
 
 }
 
+package android.os {
+
+  public final class PowerManager {
+    method public void goToSleep(long);
+    method public deprecated void userActivity(long, boolean);
+    method public void wakeUp(long);
+  }
+
+}
+
 package android.view {
 
   public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0dc8f66..41bbb87 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1373,6 +1373,8 @@
      * and its profiles or a particular one.
      * @param admin The name of the admin component to check, or null to aggregate
      * all admins.
+     * @return time in milliseconds for the given admin or the minimum value (strictest) of
+     * all admins if admin is null.
      */
     public long getMaximumTimeToLock(ComponentName admin) {
         return getMaximumTimeToLock(admin, UserHandle.myUserId());
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 75f8279..f7b0ead 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.util.Log;
 
@@ -186,8 +187,6 @@
      * </p><p>
      * Cannot be used with {@link #ACQUIRE_CAUSES_WAKEUP}.
      * </p>
-     *
-     * {@hide}
      */
     public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;
 
@@ -197,6 +196,8 @@
      * <p>
      * This is used by the dream manager to implement doze mode.  It currently
      * has no effect unless the power manager is in the dozing state.
+     * </p><p>
+     * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
      * </p>
      *
      * {@hide}
@@ -243,11 +244,9 @@
     public static final int UNIMPORTANT_FOR_LOGGING = 0x40000000;
 
     /**
-     * Flag for {@link WakeLock#release release(int)} to defer releasing a
-     * {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor returns
-     * a negative value.
-     *
-     * {@hide}
+     * Flag for {@link WakeLock#release WakeLock.release(int)}: Defer releasing a
+     * {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor
+     * indicates that an object is not in close proximity.
      */
     public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1;
 
@@ -276,28 +275,44 @@
      * User activity event type: Unspecified event type.
      * @hide
      */
+    @SystemApi
     public static final int USER_ACTIVITY_EVENT_OTHER = 0;
 
     /**
      * User activity event type: Button or key pressed or released.
      * @hide
      */
+    @SystemApi
     public static final int USER_ACTIVITY_EVENT_BUTTON = 1;
 
     /**
      * User activity event type: Touch down, move or up.
      * @hide
      */
+    @SystemApi
     public static final int USER_ACTIVITY_EVENT_TOUCH = 2;
 
     /**
-     * User activity flag: Do not restart the user activity timeout or brighten
-     * the display in response to user activity if it is already dimmed.
+     * User activity flag: If already dimmed, extend the dim timeout
+     * but do not brighten.  This flag is useful for keeping the screen on
+     * a little longer without causing a visible change such as when
+     * the power key is pressed.
      * @hide
      */
+    @SystemApi
     public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1 << 0;
 
     /**
+     * User activity flag: Note the user activity as usual but do not
+     * reset the user activity timeout.  This flag is useful for applying
+     * user activity power hints when interacting with the device indirectly
+     * on a secondary screen while allowing the primary screen to go to sleep.
+     * @hide
+     */
+    @SystemApi
+    public static final int USER_ACTIVITY_FLAG_INDIRECT = 1 << 1;
+
+    /**
      * Go to sleep reason code: Going to sleep due by application request.
      * @hide
      */
@@ -335,6 +350,12 @@
     public static final int GO_TO_SLEEP_REASON_HDMI = 5;
 
     /**
+     * Go to sleep flag: Skip dozing state and directly go to full sleep.
+     * @hide
+     */
+    public static final int GO_TO_SLEEP_FLAG_NO_DOZE = 1 << 0;
+
+    /**
      * The value to pass as the 'reason' argument to reboot() to
      * reboot into recovery mode (for applying system updates, doing
      * factory resets, etc.).
@@ -347,12 +368,6 @@
      */
     public static final String REBOOT_RECOVERY = "recovery";
     
-    /**
-     * Go to sleep flag: Skip dozing state and directly go to full sleep.
-     * @hide
-     */
-    public static final int GO_TO_SLEEP_FLAG_NO_DOZE = 1 << 0;
-
     final Context mContext;
     final IPowerManager mService;
     final Handler mHandler;
@@ -456,6 +471,7 @@
      * @see #FULL_WAKE_LOCK
      * @see #SCREEN_DIM_WAKE_LOCK
      * @see #SCREEN_BRIGHT_WAKE_LOCK
+     * @see #PROXIMITY_SCREEN_OFF_WAKE_LOCK
      * @see #ACQUIRE_CAUSES_WAKEUP
      * @see #ON_AFTER_RELEASE
      */
@@ -505,11 +521,44 @@
      *
      * @see #wakeUp
      * @see #goToSleep
+     *
+     * @removed Requires signature or system permission.
+     * @deprecated Use {@link #userActivity(long, int, int)}.
      */
+    @Deprecated
     public void userActivity(long when, boolean noChangeLights) {
+        userActivity(when, USER_ACTIVITY_EVENT_OTHER,
+                noChangeLights ? USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS : 0);
+    }
+
+    /**
+     * Notifies the power manager that user activity happened.
+     * <p>
+     * Resets the auto-off timer and brightens the screen if the device
+     * is not asleep.  This is what happens normally when a key or the touch
+     * screen is pressed or when some other user activity occurs.
+     * This method does not wake up the device if it has been put to sleep.
+     * </p><p>
+     * Requires the {@link android.Manifest.permission#DEVICE_POWER} or
+     * {@link android.Manifest.permission#USER_ACTIVITY} permission.
+     * </p>
+     *
+     * @param when The time of the user activity, in the {@link SystemClock#uptimeMillis()}
+     * time base.  This timestamp is used to correctly order the user activity request with
+     * other power management functions.  It should be set
+     * to the timestamp of the input event that caused the user activity.
+     * @param event The user activity event.
+     * @param flags Optional user activity flags.
+     *
+     * @see #wakeUp
+     * @see #goToSleep
+     *
+     * @hide Requires signature or system permission.
+     */
+    @SystemApi
+    public void userActivity(long when, int event, int flags) {
         try {
-            mService.userActivity(when, USER_ACTIVITY_EVENT_OTHER,
-                    noChangeLights ? USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS : 0);
+            mService.userActivity(when, event, flags);
         } catch (RemoteException e) {
         }
     }
@@ -530,13 +579,33 @@
      *
      * @see #userActivity
      * @see #wakeUp
+     *
+     * @removed Requires signature permission.
      */
     public void goToSleep(long time) {
         goToSleep(time, GO_TO_SLEEP_REASON_APPLICATION, 0);
     }
 
     /**
-     * @hide
+     * Forces the device to go to sleep.
+     * <p>
+     * Overrides all the wake locks that are held.
+     * This is what happens when the power key is pressed to turn off the screen.
+     * </p><p>
+     * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+     * </p>
+     *
+     * @param time The time when the request to go to sleep was issued, in the
+     * {@link SystemClock#uptimeMillis()} time base.  This timestamp is used to correctly
+     * order the go to sleep request with other power management functions.  It should be set
+     * to the timestamp of the input event that caused the request to go to sleep.
+     * @param reason The reason the device is going to sleep.
+     * @param flags Optional flags to apply when going to sleep.
+     *
+     * @see #userActivity
+     * @see #wakeUp
+     *
+     * @hide Requires signature permission.
      */
     public void goToSleep(long time, int reason, int flags) {
         try {
@@ -561,6 +630,8 @@
      *
      * @see #userActivity
      * @see #goToSleep
+     *
+     * @removed Requires signature permission.
      */
     public void wakeUp(long time) {
         try {
@@ -588,7 +659,7 @@
      * @see #wakeUp
      * @see #goToSleep
      *
-     * @hide
+     * @hide Requires signature permission.
      */
     public void nap(long time) {
         try {
@@ -605,7 +676,7 @@
      *
      * @param brightness The brightness value from 0 to 255.
      *
-     * {@hide}
+     * @hide Requires signature permission.
      */
     public void setBacklightBrightness(int brightness) {
         try {
@@ -619,8 +690,6 @@
      *
      * @param level The wake lock level to check.
      * @return True if the specified wake lock level is supported.
-     *
-     * {@hide}
      */
     public boolean isWakeLockLevelSupported(int level) {
         try {
@@ -893,8 +962,6 @@
          *
          * @param flags Combination of flag values to modify the release behavior.
          * Currently only {@link #WAIT_FOR_PROXIMITY_NEGATIVE} is supported.
-         *
-         * {@hide}
          */
         public void release(int flags) {
             synchronized (mToken) {
diff --git a/core/java/android/service/trust/ITrustAgentService.aidl b/core/java/android/service/trust/ITrustAgentService.aidl
index 637d080..bd80a3f 100644
--- a/core/java/android/service/trust/ITrustAgentService.aidl
+++ b/core/java/android/service/trust/ITrustAgentService.aidl
@@ -24,6 +24,7 @@
  */
 interface ITrustAgentService {
     oneway void onUnlockAttempt(boolean successful);
+    oneway void onTrustTimeout();
     oneway void setCallback(ITrustAgentServiceCallback callback);
     oneway void setTrustAgentFeaturesEnabled(in Bundle options, IBinder token);
 }
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 5fe9194..337ae60 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -30,6 +30,7 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.util.Log;
 import android.util.Slog;
 
@@ -37,7 +38,10 @@
  * 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>Trust agents may only be provided by the platform. It is expected that there is only
+ * one trust agent installed on the platform. In the event there is more than one,
+ * either trust agent can enable trust.
+ * </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
@@ -90,6 +94,7 @@
 
     private static final int MSG_UNLOCK_ATTEMPT = 1;
     private static final int MSG_SET_TRUST_AGENT_FEATURES_ENABLED = 2;
+    private static final int MSG_TRUST_TIMEOUT = 3;
 
     private ITrustAgentServiceCallback mCallback;
 
@@ -118,6 +123,9 @@
                         onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
                     }
                     break;
+                case MSG_TRUST_TIMEOUT:
+                    onTrustTimeout();
+                    break;
             }
         }
     };
@@ -139,21 +147,32 @@
     }
 
     /**
-     * Called when the user attempted to authenticate on the device.
+     * Called after the user attempts to authenticate in keyguard with their device credentials,
+     * such as pin, pattern or password.
      *
-     * @param successful true if the attempt succeeded
+     * @param successful true if the user successfully completed the challenge.
      */
     public void onUnlockAttempt(boolean successful) {
     }
 
+    /**
+     * Called when the timeout provided by the agent expires.  Note that this may be called earlier
+     * than requested by the agent if the trust timeout is adjusted by the system or
+     * {@link DevicePolicyManager}.  The agent is expected to re-evaluate the trust state and only
+     * call {@link #grantTrust(CharSequence, long, boolean)} if the trust state should be
+     * continued.
+     */
+    public void onTrustTimeout() {
+    }
+
     private void onError(String msg) {
         Slog.v(TAG, "Remote exception while " + msg);
     }
 
     /**
-     * Called when device policy wants to restrict features in the TrustAgent in response to
+     * Called when device policy wants to restrict features in the agent in response to
      * {@link DevicePolicyManager#setTrustAgentFeaturesEnabled(ComponentName, ComponentName, java.util.List) }.
-     * TrustAgents that support this feature should overload this method and return 'true'.
+     * Agents that support this feature should overload this method and return 'true'.
      *
      * The list of options can be obtained by calling
      * options.getStringArrayList({@link #KEY_FEATURES}). Presence of a feature string in the list
@@ -174,10 +193,19 @@
      * Call to grant trust on the device.
      *
      * @param message describes why the device is trusted, e.g. "Trusted by location".
-     * @param durationMs amount of time in milliseconds to keep the device in a trusted state. Trust
-     *                   for this agent will automatically be revoked when the timeout expires.
-     * @param initiatedByUser indicates that the user has explicitly initiated an action that proves
-     *                        the user is about to use the device.
+     * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
+     *    Trust for this agent will automatically be revoked when the timeout expires unless
+     *    extended by a subsequent call to this function. The timeout is measured from the
+     *    invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
+     *    For security reasons, the value should be no larger than necessary.
+     *    The value may be adjusted by the system as necessary to comply with a policy controlled
+     *    by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
+     *    for determining when trust expires.
+     * @param initiatedByUser this is a hint to the system that trust is being granted as the
+     *    direct result of user action - such as solving a security challenge. The hint is used
+     *    by the system to optimize the experience. Behavior may vary by device and release, so
+     *    one should only set this parameter if it meets the above criteria rather than relying on
+     *    the behavior of any particular device or release.
      * @throws IllegalStateException if the agent is not currently managing trust.
      */
     public final void grantTrust(
@@ -254,13 +282,17 @@
     }
 
     private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
-        @Override
+        @Override /* Binder API */
         public void onUnlockAttempt(boolean successful) {
-            mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0)
-                    .sendToTarget();
+            mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget();
         }
 
-        @Override
+        @Override /* Binder API */
+        public void onTrustTimeout() {
+            mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
+        }
+
+        @Override /* Binder API */
         public void setCallback(ITrustAgentServiceCallback callback) {
             synchronized (mLock) {
                 mCallback = callback;
@@ -280,7 +312,7 @@
             }
         }
 
-        @Override
+        @Override /* Binder API */
         public void setTrustAgentFeaturesEnabled(Bundle features, IBinder token) {
             Message msg = mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_ENABLED, token);
             msg.setData(features);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 096fe88..9b3a1e0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5719,8 +5719,6 @@
         }
 
         if (mEditor != null && mEditor.mKeyListener != null) {
-            resetErrorChangedFlag();
-
             boolean doDown = true;
             if (otherEvent != null) {
                 try {
@@ -7637,6 +7635,7 @@
                 list.get(i).afterTextChanged(text);
             }
         }
+        hideErrorIfUnchanged();
     }
 
     void updateAfterEdit() {
@@ -7676,7 +7675,7 @@
             }
             ims.mChangedDelta += after-before;
         }
-
+        resetErrorChangedFlag();
         sendOnTextChanged(buffer, start, before, after);
         onTextChanged(buffer, start, before, after);
     }
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 1b89179..ae44047 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -37,6 +37,8 @@
 import java.util.Calendar;
 import java.util.Locale;
 
+import libcore.icu.LocaleData;
+
 import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
 import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
 
@@ -143,11 +145,8 @@
         mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
         mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
-            /* Get the localized am/pm strings and use them in the spinner */
-        final Resources res = context.getResources();
-        final String amText = res.getString(R.string.time_picker_am_label);
-        final String pmText = res.getString(R.string.time_picker_pm_label);
-        mAmPmStrings = new String[] {amText, pmText};
+        // Get the localized am/pm strings and use them in the spinner.
+        mAmPmStrings = getAmPmStrings(context);
 
         // am/pm
         View amPmView = mDelegator.findViewById(R.id.amPm);
@@ -601,5 +600,12 @@
             }
         };
     }
-}
 
+    public static String[] getAmPmStrings(Context context) {
+        String[] result = new String[2];
+        LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
+        result[0] = d.amPm[0].length() > 2 ? d.narrowAm : d.amPm[0];
+        result[1] = d.amPm[1].length() > 2 ? d.narrowPm : d.amPm[1];
+        return result;
+    }
+}
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 9a50250..dd1bf4f 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -127,8 +127,10 @@
         mSelectHours = res.getString(R.string.select_hours);
         mMinutePickerDescription = res.getString(R.string.minute_picker_description);
         mSelectMinutes = res.getString(R.string.select_minutes);
-        mAmText = res.getString(R.string.time_picker_am_label);
-        mPmText = res.getString(R.string.time_picker_pm_label);
+
+        String[] amPmStrings = TimePickerClockDelegate.getAmPmStrings(context);
+        mAmText = amPmStrings[0];
+        mPmText = amPmStrings[1];
 
         final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
                 R.layout.time_picker_holo);
diff --git a/core/java/com/android/internal/net/LegacyVpnInfo.java b/core/java/com/android/internal/net/LegacyVpnInfo.java
index f812ad6..d6f6d0b 100644
--- a/core/java/com/android/internal/net/LegacyVpnInfo.java
+++ b/core/java/com/android/internal/net/LegacyVpnInfo.java
@@ -40,6 +40,7 @@
 
     public String key;
     public int state = -1;
+    public PendingIntent intent;
 
     @Override
     public int describeContents() {
@@ -50,6 +51,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(key);
         out.writeInt(state);
+        out.writeParcelable(intent, flags);
     }
 
     public static final Parcelable.Creator<LegacyVpnInfo> CREATOR =
@@ -59,6 +61,7 @@
             LegacyVpnInfo info = new LegacyVpnInfo();
             info.key = in.readString();
             info.state = in.readInt();
+            info.intent = in.readParcelable(null);
             return info;
         }
 
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index aa66d7d..9c3f419 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -28,6 +28,7 @@
 import android.net.RouteInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 
 import java.net.Inet4Address;
 import java.net.InetAddress;
@@ -57,6 +58,15 @@
         return intent;
     }
 
+    /** NOTE: This should only be used for legacy VPN. */
+    public static PendingIntent getIntentForStatusPanel(Context context) {
+        Intent intent = new Intent();
+        intent.setClassName(DIALOGS_PACKAGE, DIALOGS_PACKAGE + ".ManageDialog");
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY |
+                Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        return PendingIntent.getActivityAsUser(context, 0, intent, 0, null, UserHandle.CURRENT);
+    }
+
     public static CharSequence getVpnLabel(Context context, String packageName)
             throws NameNotFoundException {
         PackageManager pm = context.getPackageManager();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0a395e1..672ad84 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2408,6 +2408,13 @@
         android:description="@string/permdesc_devicePower"
         android:protectionLevel="signature" />
 
+   <!-- Allows access to the PowerManager.userActivity function.
+   <p>Not for use by third-party applications. @hide @SystemApi -->
+    <permission android:name="android.permission.USER_ACTIVITY"
+        android:label="@string/permlab_userActivity"
+        android:description="@string/permdesc_userActivity"
+        android:protectionLevel="signature|system" />
+
    <!-- @hide Allows low-level access to tun tap driver -->
     <permission android:name="android.permission.NET_TUNNELING"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
diff --git a/core/res/res/values-television/styles.xml b/core/res/res/values-television/styles.xml
new file mode 100644
index 0000000..4c0562f
--- /dev/null
+++ b/core/res/res/values-television/styles.xml
@@ -0,0 +1,22 @@
+<!-- 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.
+-->
+
+<resources>
+    <style name="Lighting">
+        <item name="lightY">-300dp</item>
+        <item name="ambientShadowAlpha">0.4</item>
+        <item name="spotShadowAlpha">0.4</item>
+    </style>
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c6478ab..4f0757c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -673,6 +673,37 @@
     -->
     <integer name="config_doubleTapOnHomeBehavior">0</integer>
 
+    <!-- Minimum screen brightness setting allowed by the power manager.
+         The user is forbidden from setting the brightness below this level. -->
+    <integer name="config_screenBrightnessSettingMinimum">10</integer>
+
+    <!-- Maximum screen brightness allowed by the power manager.
+         The user is forbidden from setting the brightness above this level. -->
+    <integer name="config_screenBrightnessSettingMaximum">255</integer>
+
+    <!-- Default screen brightness setting.
+         Must be in the range specified by minimum and maximum. -->
+    <integer name="config_screenBrightnessSettingDefault">102</integer>
+
+    <!-- Screen brightness used to dim the screen while dozing in a very low power state.
+         May be less than the minimum allowed brightness setting
+         that can be set by the user. -->
+    <integer name="config_screenBrightnessDoze">1</integer>
+
+    <!-- Screen brightness used to dim the screen when the user activity
+         timeout expires.  May be less than the minimum allowed brightness setting
+         that can be set by the user. -->
+    <integer name="config_screenBrightnessDim">10</integer>
+
+    <!-- Minimum allowable screen brightness to use in a very dark room.
+         This value sets the floor for the darkest possible auto-brightness
+         adjustment.  It is expected to be somewhat less than the first entry in
+         config_autoBrightnessLcdBacklightValues so as to allow the user to have
+         some range of adjustment to dim the screen further than usual in very
+         dark rooms. The contents of the screen must still be clearly visible
+         in darkness (although they may not be visible in a bright room). -->
+    <integer name="config_screenBrightnessDark">1</integer>
+
     <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support.
          The N entries of this array define N + 1 control points as follows:
          (1-based arrays)
@@ -696,28 +727,6 @@
     <integer-array name="config_autoBrightnessLevels">
     </integer-array>
 
-    <!-- Minimum screen brightness setting allowed by the power manager.
-         The user is forbidden from setting the brightness below this level. -->
-    <integer name="config_screenBrightnessSettingMinimum">10</integer>
-
-    <!-- Maximum screen brightness allowed by the power manager.
-         The user is forbidden from setting the brightness above this level. -->
-    <integer name="config_screenBrightnessSettingMaximum">255</integer>
-
-    <!-- Default screen brightness setting.
-         Must be in the range specified by minimum and maximum. -->
-    <integer name="config_screenBrightnessSettingDefault">102</integer>
-
-    <!-- Screen brightness used to dim the screen while dozing in a very low power state.
-         May be less than the minimum allowed brightness setting
-         that can be set by the user. -->
-    <integer name="config_screenBrightnessDoze">1</integer>
-
-    <!-- Screen brightness used to dim the screen when the user activity
-         timeout expires.  May be less than the minimum allowed brightness setting
-         that can be set by the user. -->
-    <integer name="config_screenBrightnessDim">10</integer>
-
     <!-- Array of output values for LCD backlight corresponding to the LUX values
          in the config_autoBrightnessLevels array.  This array should have size one greater
          than the size of the config_autoBrightnessLevels array.
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1453e15..b167c0a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1815,6 +1815,11 @@
     <string name="permdesc_devicePower" product="default">Allows the app to turn the phone on or off.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_userActivity">reset display timeout</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_userActivity">Allows the app to reset the display timeout.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_factoryTest">run in factory test mode</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_factoryTest" product="tablet">Run as a low-level manufacturer test,
@@ -4142,10 +4147,6 @@
     <string name="time_picker_increment_set_pm_button">Set PM</string>
     <!-- Description of the button to decrease the TimePicker's set AM value. [CHAR LIMIT=NONE] -->
     <string name="time_picker_decrement_set_am_button">Set AM</string>
-    <!-- Label for the TimePicker's PM button. [CHAR LIMIT=2] -->
-    <string name="time_picker_pm_label">PM</string>
-    <!-- Label for the TimePicker's AM button. [CHAR LIMIT=2] -->
-    <string name="time_picker_am_label">AM</string>
 
     <!-- DatePicker - accessibility support -->
     <!-- Description of the button to increase the DatePicker's month value. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b5ec56a..3f373aa 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1565,6 +1565,7 @@
   <java-symbol type="integer" name="config_screenBrightnessSettingMinimum" />
   <java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
   <java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
+  <java-symbol type="integer" name="config_screenBrightnessDark" />
   <java-symbol type="integer" name="config_screenBrightnessDim" />
   <java-symbol type="integer" name="config_screenBrightnessDoze" />
   <java-symbol type="integer" name="config_shutdownBatteryTemperature" />
@@ -1985,8 +1986,6 @@
   <java-symbol type="attr" name="headerSelectedTextColor" />
   <java-symbol type="attr" name="amPmSelectedBackgroundColor" />
   <java-symbol type="bool" name="config_sms_decode_gsm_8bit_data" />
-  <java-symbol type="string" name="time_picker_am_label" />
-  <java-symbol type="string" name="time_picker_pm_label" />
   <java-symbol type="dimen" name="text_size_small_material" />
   <java-symbol type="attr" name="checkMarkGravity" />
   <java-symbol type="layout" name="select_dialog_singlechoice_material" />
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index b4b0e53..01995c7 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -127,10 +127,11 @@
         assertTrue("failed to connect to " + mTestAccessPoint,
                 connectToWifi(mTestAccessPoint));
         // assert that WifiManager reports correct state
-        assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
+        assertTrue("wifi not enabled", waitForWifiState(
+                WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
         // assert that ConnectivityManager reports correct state for Wifi
-        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                WIFI_CONNECTION_TIMEOUT));
+        assertTrue("wifi not connected", waitForNetworkState(
+                ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
         // below check disbabled since we have bug in what ConnectivityManager returns
 //        if (!mWifiOnlyFlag) {
 //            // assert that ConnectivityManager reports correct state for mobile
@@ -267,8 +268,8 @@
         // connect to Wifi
         assertTrue("failed to connect to " + mTestAccessPoint,
                 connectToWifi(mTestAccessPoint));
-        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                WIFI_CONNECTION_TIMEOUT));
+        assertTrue("wifi not connected", waitForNetworkState(
+                ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
         // verify that connection actually works
         assertTrue("no network connectivity after wifi enable", checkNetworkConnectivity());
 
@@ -289,8 +290,8 @@
         // connect to Wifi
         assertTrue("failed to connect to " + mTestAccessPoint,
                 connectToWifi(mTestAccessPoint));
-        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                WIFI_CONNECTION_TIMEOUT));
+        assertTrue("wifi not connected", waitForNetworkState(
+                ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
 
         // enable airplane mode without clearing Wifi
         mCm.setAirplaneMode(true);
@@ -322,8 +323,8 @@
         // connect to Wifi
         assertTrue("failed to connect to " + mTestAccessPoint,
                 connectToWifi(mTestAccessPoint));
-        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                WIFI_CONNECTION_TIMEOUT));
+        assertTrue("wifi not connected", waitForNetworkState(
+                ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
         assertNotNull("not associated with any AP", mWifiManager.getConnectionInfo().getBSSID());
 
         // disconnect from the current AP
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 859c30c..6ef4f06 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -198,6 +198,9 @@
     // Stress Wifi reconnection to secure net after sleep
     @LargeTest
     public void testWifiReconnectionAfterSleep() {
+        // set always scan to false
+        Settings.Global.putInt(mRunner.getContext().getContentResolver(),
+                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
         // set wifi sleep policy to never on while in sleep
         Settings.Global.putInt(mRunner.getContext().getContentResolver(),
                 Settings.Global.WIFI_SLEEP_POLICY, Settings.Global.WIFI_SLEEP_POLICY_NEVER);
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
index 4ea1c77..c650a0f 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
@@ -76,6 +76,12 @@
     }
 
     @Override
+    public void onTrustTimeout() {
+        super.onTrustTimeout();
+        Toast.makeText(this, "onTrustTimeout(): timeout expired", Toast.LENGTH_SHORT).show();
+    }
+
+    @Override
     public void onUnlockAttempt(boolean successful) {
         if (getReportUnlockAttempts(this)) {
             Toast.makeText(this, "onUnlockAttempt(successful=" + successful + ")",
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 1768400..03d920a 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -28,5 +28,14 @@
                 <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
+
+        <activity android:name=".ManageDialog"
+                android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+                android:noHistory="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/packages/VpnDialogs/res/layout/manage.xml b/packages/VpnDialogs/res/layout/manage.xml
new file mode 100644
index 0000000..6b504e4
--- /dev/null
+++ b/packages/VpnDialogs/res/layout/manage.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="3mm"
+        android:stretchColumns="0,1"
+        android:shrinkColumns="1">
+
+    <TableRow>
+        <TextView android:text="@string/session" style="@style/label"/>
+        <TextView android:id="@+id/session" style="@style/value"/>
+    </TableRow>
+
+    <TableRow>
+        <TextView android:text="@string/duration" style="@style/label"/>
+        <TextView android:id="@+id/duration" style="@style/value"/>
+    </TableRow>
+
+    <TableRow android:id="@+id/data_transmitted_row" android:visibility="gone">
+        <TextView android:text="@string/data_transmitted" style="@style/label"/>
+        <TextView android:id="@+id/data_transmitted" style="@style/value"/>
+    </TableRow>
+
+    <TableRow android:id="@+id/data_received_row" android:visibility="gone">
+        <TextView android:text="@string/data_received" style="@style/label"/>
+        <TextView android:id="@+id/data_received" style="@style/value"/>
+    </TableRow>
+
+</TableLayout>
+
diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml
index 84206a1..406bcc3 100644
--- a/packages/VpnDialogs/res/values/strings.xml
+++ b/packages/VpnDialogs/res/values/strings.xml
@@ -28,4 +28,26 @@
         <img src="vpn_icon" />
         ]]> appears at the top of your screen when VPN is active.
     </string>
+
+    <!-- Dialog title for built-in VPN. [CHAR LIMIT=40]  -->
+    <string name="legacy_title">VPN is connected</string>
+    <!-- Button label to configure the current VPN session. [CHAR LIMIT=20] -->
+    <string name="configure">Configure</string>
+    <!-- Button label to disconnect the current VPN session. [CHAR LIMIT=20] -->
+    <string name="disconnect">Disconnect</string>
+
+    <!-- Label for the name of the current VPN session. [CHAR LIMIT=20] -->
+    <string name="session">Session:</string>
+    <!-- Label for the duration of the current VPN session. [CHAR LIMIT=20] -->
+    <string name="duration">Duration:</string>
+    <!-- Label for the network usage of data transmitted over VPN. [CHAR LIMIT=20] -->
+    <string name="data_transmitted">Sent:</string>
+    <!-- Label for the network usage of data received over VPN. [CHAR LIMIT=20] -->
+    <string name="data_received">Received:</string>
+
+    <!-- Formatted string for the network usage over VPN. [CHAR LIMIT=40] -->
+    <string name="data_value_format">
+        <xliff:g id="number">%1$s</xliff:g> bytes /
+        <xliff:g id="number">%2$s</xliff:g> packets
+    </string>
 </resources>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
new file mode 100644
index 0000000..cc8500a
--- /dev/null
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2011 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.vpndialogs;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.IConnectivityManager;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.net.VpnConfig;
+
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+
+public class ManageDialog extends AlertActivity implements
+        DialogInterface.OnClickListener, Handler.Callback {
+    private static final String TAG = "VpnManage";
+
+    private VpnConfig mConfig;
+
+    private IConnectivityManager mService;
+
+    private TextView mDuration;
+    private TextView mDataTransmitted;
+    private TextView mDataReceived;
+    private boolean mDataRowsHidden;
+
+    private Handler mHandler;
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        if (getCallingPackage() != null) {
+            Log.e(TAG, getCallingPackage() + " cannot start this activity");
+            finish();
+            return;
+        }
+
+        try {
+
+            mService = IConnectivityManager.Stub.asInterface(
+                    ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+
+            mConfig = mService.getVpnConfig();
+
+            // mConfig can be null if we are a restricted user, in that case don't show this dialog
+            if (mConfig == null) {
+                finish();
+                return;
+            }
+
+            View view = View.inflate(this, R.layout.manage, null);
+            if (mConfig.session != null) {
+                ((TextView) view.findViewById(R.id.session)).setText(mConfig.session);
+            }
+            mDuration = (TextView) view.findViewById(R.id.duration);
+            mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted);
+            mDataReceived = (TextView) view.findViewById(R.id.data_received);
+            mDataRowsHidden = true;
+
+            if (mConfig.legacy) {
+                mAlertParams.mTitle = getText(R.string.legacy_title);
+            } else {
+                mAlertParams.mTitle = VpnConfig.getVpnLabel(this, mConfig.user);
+            }
+            if (mConfig.configureIntent != null) {
+                mAlertParams.mPositiveButtonText = getText(R.string.configure);
+                mAlertParams.mPositiveButtonListener = this;
+            }
+            mAlertParams.mNeutralButtonText = getText(R.string.disconnect);
+            mAlertParams.mNeutralButtonListener = this;
+            mAlertParams.mNegativeButtonText = getText(android.R.string.cancel);
+            mAlertParams.mNegativeButtonListener = this;
+            mAlertParams.mView = view;
+            setupAlert();
+
+            if (mHandler == null) {
+                mHandler = new Handler(this);
+            }
+            mHandler.sendEmptyMessage(0);
+        } catch (Exception e) {
+            Log.e(TAG, "onResume", e);
+            finish();
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        if (!isFinishing()) {
+            finish();
+        }
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        try {
+            if (which == DialogInterface.BUTTON_POSITIVE) {
+                mConfig.configureIntent.send();
+            } else if (which == DialogInterface.BUTTON_NEUTRAL) {
+                if (mConfig.legacy) {
+                    mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+                } else {
+                    mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
+                }
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "onClick", e);
+            finish();
+        }
+    }
+
+    @Override
+    public boolean handleMessage(Message message) {
+        mHandler.removeMessages(0);
+
+        if (!isFinishing()) {
+            if (mConfig.startTime != -1) {
+                long seconds = (SystemClock.elapsedRealtime() - mConfig.startTime) / 1000;
+                mDuration.setText(String.format("%02d:%02d:%02d",
+                        seconds / 3600, seconds / 60 % 60, seconds % 60));
+            }
+
+            String[] numbers = getNumbers();
+            if (numbers != null) {
+                // First unhide the related data rows.
+                if (mDataRowsHidden) {
+                    findViewById(R.id.data_transmitted_row).setVisibility(View.VISIBLE);
+                    findViewById(R.id.data_received_row).setVisibility(View.VISIBLE);
+                    mDataRowsHidden = false;
+                }
+
+                // [1] and [2] are received data in bytes and packets.
+                mDataReceived.setText(getString(R.string.data_value_format,
+                        numbers[1], numbers[2]));
+
+                // [9] and [10] are transmitted data in bytes and packets.
+                mDataTransmitted.setText(getString(R.string.data_value_format,
+                        numbers[9], numbers[10]));
+            }
+            mHandler.sendEmptyMessageDelayed(0, 1000);
+        }
+        return true;
+    }
+
+    private String[] getNumbers() {
+        DataInputStream in = null;
+        try {
+            // See dev_seq_printf_stats() in net/core/dev.c.
+            in = new DataInputStream(new FileInputStream("/proc/net/dev"));
+            String prefix = mConfig.interfaze + ':';
+
+            while (true) {
+                String line = in.readLine().trim();
+                if (line.startsWith(prefix)) {
+                    String[] numbers = line.substring(prefix.length()).split(" +");
+                    for (int i = 1; i < 17; ++i) {
+                        if (!numbers[i].equals("0")) {
+                            return numbers;
+                        }
+                    }
+                    break;
+                }
+            }
+        } catch (Exception e) {
+            // ignore
+        } finally {
+            try {
+                in.close();
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+        return null;
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
index 394c196..38827d0 100644
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
@@ -60,15 +60,17 @@
     public static boolean hasAdjustments(Context context, int userId) {
         final ContentResolver cr = context.getContentResolver();
 
-        boolean hasColorTransform = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1;
-
-        if (!hasColorTransform) {
-            hasColorTransform |= Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) == 1;
+        if (Settings.Secure.getIntForUser(cr,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) {
+            return true;
         }
 
-        return hasColorTransform;
+        if (Settings.Secure.getIntForUser(cr,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
+            return true;
+        }
+
+        return false;
     }
 
     /**
@@ -76,52 +78,39 @@
      */
     public static void applyAdjustments(Context context, int userId) {
         final ContentResolver cr = context.getContentResolver();
-        float[] colorMatrix = new float[16];
-        float[] outputMatrix = new float[16];
-        boolean hasColorTransform = false;
+        float[] colorMatrix = null;
 
-        Matrix.setIdentityM(colorMatrix, 0);
-
-        final boolean inversionEnabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1;
-        if (inversionEnabled) {
-            final float[] inversionMatrix = INVERSION_MATRIX_VALUE_ONLY;
-            Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, inversionMatrix, 0);
-
-            colorMatrix = outputMatrix;
-            outputMatrix = colorMatrix;
-
-            hasColorTransform = true;
+        if (Settings.Secure.getIntForUser(cr,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0) {
+            colorMatrix = multiply(colorMatrix, INVERSION_MATRIX_VALUE_ONLY);
         }
 
-        final boolean daltonizerEnabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0;
-        if (daltonizerEnabled) {
+        if (Settings.Secure.getIntForUser(cr,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
             final int daltonizerMode = Settings.Secure.getIntForUser(cr,
                     Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER,
                     userId);
             // Monochromacy isn't supported by the native Daltonizer.
             if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
-                Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, GRAYSCALE_MATRIX, 0);
-
-                final float[] temp = colorMatrix;
-                colorMatrix = outputMatrix;
-                outputMatrix = temp;
-
-                hasColorTransform = true;
-                nativeSetDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
+                colorMatrix = multiply(colorMatrix, GRAYSCALE_MATRIX);
+                setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
             } else {
-                nativeSetDaltonizerMode(daltonizerMode);
+                setDaltonizerMode(daltonizerMode);
             }
         } else {
-            nativeSetDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
+            setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
         }
 
-        if (hasColorTransform) {
-            nativeSetColorTransform(colorMatrix);
-        } else {
-            nativeSetColorTransform(null);
+        setColorTransform(colorMatrix);
+    }
+
+    private static float[] multiply(float[] matrix, float[] other) {
+        if (matrix == null) {
+            return other;
         }
+        float[] result = new float[16];
+        Matrix.multiplyMM(result, 0, matrix, 0, other, 0);
+        return result;
     }
 
     /**
@@ -130,7 +119,7 @@
      *
      * @param mode new Daltonization mode
      */
-    private static void nativeSetDaltonizerMode(int mode) {
+    private static void setDaltonizerMode(int mode) {
         try {
             final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
             if (flinger != null) {
@@ -152,7 +141,7 @@
      * @param m the float array that holds the transformation matrix, or null to
      *            disable transformation
      */
-    private static void nativeSetColorTransform(float[] m) {
+    private static void setColorTransform(float[] m) {
         try {
             final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
             if (flinger != null) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 69caab9..94aa421 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -22,6 +22,7 @@
 
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -105,6 +106,7 @@
     private boolean mAllowIPv6;
     private Connection mConnection;
     private LegacyVpnRunner mLegacyVpnRunner;
+    private PendingIntent mStatusIntent;
     private volatile boolean mEnableTeardown = true;
     private final IConnectivityManager mConnService;
     private final INetworkManagementService mNetd;
@@ -237,6 +239,7 @@
 
         // Reset the interface.
         if (mInterface != null) {
+            mStatusIntent = null;
             agentDisconnect();
             jniReset(mInterface);
             mInterface = null;
@@ -567,17 +570,20 @@
 
         // add the user
         mVpnUsers.add(UidRange.createForUser(user));
+
+        prepareStatusIntent();
     }
 
     private void removeVpnUserLocked(int user) {
-            if (!isRunningLocked()) {
-                throw new IllegalStateException("VPN is not active");
-            }
-            UidRange uidRange = UidRange.createForUser(user);
-            if (mNetworkAgent != null) {
-                mNetworkAgent.removeUidRanges(new UidRange[] { uidRange });
-            }
-            mVpnUsers.remove(uidRange);
+        if (!isRunningLocked()) {
+            throw new IllegalStateException("VPN is not active");
+        }
+        UidRange uidRange = UidRange.createForUser(user);
+        if (mNetworkAgent != null) {
+            mNetworkAgent.removeUidRanges(new UidRange[] { uidRange });
+        }
+        mVpnUsers.remove(uidRange);
+        mStatusIntent = null;
     }
 
     private void onUserAdded(int userId) {
@@ -645,6 +651,7 @@
         public void interfaceRemoved(String interfaze) {
             synchronized (Vpn.this) {
                 if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
+                    mStatusIntent = null;
                     mVpnUsers = null;
                     mInterface = null;
                     if (mConnection != null) {
@@ -702,6 +709,15 @@
         }
     }
 
+    private void prepareStatusIntent() {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     public synchronized boolean addAddress(String address, int prefixLength) {
         if (Binder.getCallingUid() != mOwnerUID || mInterface == null || mNetworkAgent == null) {
             return false;
@@ -911,6 +927,9 @@
         final LegacyVpnInfo info = new LegacyVpnInfo();
         info.key = mConfig.user;
         info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo);
+        if (mNetworkInfo.isConnected()) {
+            info.intent = mStatusIntent;
+        }
         return info;
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 2a1ceaa..38077eb 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -139,6 +139,9 @@
     // The dim screen brightness.
     private final int mScreenBrightnessDimConfig;
 
+    // The minimum screen brightness to use in a very dark room.
+    private final int mScreenBrightnessDarkConfig;
+
     // The minimum allowed brightness.
     private final int mScreenBrightnessRangeMinimum;
 
@@ -247,6 +250,8 @@
         mContext = context;
 
         final Resources resources = context.getResources();
+        final int screenBrightnessSettingMinimum = clampAbsoluteBrightness(resources.getInteger(
+                com.android.internal.R.integer.config_screenBrightnessSettingMinimum));
 
         mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
                 com.android.internal.R.integer.config_screenBrightnessDoze));
@@ -254,9 +259,23 @@
         mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
                 com.android.internal.R.integer.config_screenBrightnessDim));
 
-        int screenBrightnessRangeMinimum = clampAbsoluteBrightness(Math.min(resources.getInteger(
-                com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
-                mScreenBrightnessDimConfig));
+        mScreenBrightnessDarkConfig = clampAbsoluteBrightness(resources.getInteger(
+                com.android.internal.R.integer.config_screenBrightnessDark));
+        if (mScreenBrightnessDarkConfig > mScreenBrightnessDimConfig) {
+            Slog.w(TAG, "Expected config_screenBrightnessDark ("
+                    + mScreenBrightnessDarkConfig + ") to be less than or equal to "
+                    + "config_screenBrightnessDim (" + mScreenBrightnessDimConfig + ").");
+        }
+        if (mScreenBrightnessDarkConfig > mScreenBrightnessDimConfig) {
+            Slog.w(TAG, "Expected config_screenBrightnessDark ("
+                    + mScreenBrightnessDarkConfig + ") to be less than or equal to "
+                    + "config_screenBrightnessSettingMinimum ("
+                    + screenBrightnessSettingMinimum + ").");
+        }
+
+        int screenBrightnessRangeMinimum = Math.min(Math.min(
+                screenBrightnessSettingMinimum, mScreenBrightnessDimConfig),
+                mScreenBrightnessDarkConfig);
 
         mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
 
@@ -280,8 +299,15 @@
                         + "Auto-brightness will be disabled.");
                 mUseSoftwareAutoBrightnessConfig = false;
             } else {
-                if (screenBrightness[0] < screenBrightnessRangeMinimum) {
-                    screenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightness[0]);
+                int bottom = clampAbsoluteBrightness(screenBrightness[0]);
+                if (mScreenBrightnessDarkConfig > bottom) {
+                    Slog.w(TAG, "config_screenBrightnessDark (" + mScreenBrightnessDarkConfig
+                            + ") should be less than or equal to the first value of "
+                            + "config_autoBrightnessLcdBacklightValues ("
+                            + bottom + ").");
+                }
+                if (bottom < screenBrightnessRangeMinimum) {
+                    screenBrightnessRangeMinimum = bottom;
                 }
                 mAutomaticBrightnessController = new AutomaticBrightnessController(this,
                         handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
@@ -905,6 +931,7 @@
         pw.println("Display Power Controller Configuration:");
         pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
         pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
+        pw.println("  mScreenBrightnessDarkConfig=" + mScreenBrightnessDarkConfig);
         pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
         pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
         pw.println("  mUseSoftwareAutoBrightnessConfig="
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9734bd4..f47a07c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -160,9 +160,9 @@
     // Poll interval in milliseconds for watching boot animation finished.
     private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
 
-    // Used to send the hint to the PowerHAL indicating transitions
-    // from and to the low power mode.
-    private static final int POWER_HINT_LOW_POWER_MODE = 5;
+    // Power hints defined in hardware/libhardware/include/hardware/power.h.
+    private static final int POWER_HINT_INTERACTION = 2;
+    private static final int POWER_HINT_LOW_POWER = 5;
 
     private final Context mContext;
     private final ServiceThread mHandlerThread;
@@ -223,6 +223,9 @@
     private long mLastUserActivityTime;
     private long mLastUserActivityTimeNoChangeLights;
 
+    // Timestamp of last interactive power hint.
+    private long mLastInteractivePowerHintTime;
+
     // A bitfield that summarizes the effect of the user activity timer.
     // A zero value indicates that the user activity timer has expired.
     private int mUserActivitySummary;
@@ -707,7 +710,7 @@
         final boolean lowPowerModeEnabled = mLowPowerModeSetting;
         if (mLowPowerModeEnabled != lowPowerModeEnabled) {
             mLowPowerModeEnabled = lowPowerModeEnabled;
-            powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
+            powerHintInternal(POWER_HINT_LOW_POWER, lowPowerModeEnabled ? 1 : 0);
             mLowPowerModeEnabled = lowPowerModeEnabled;
             BackgroundThread.getHandler().post(new Runnable() {
                 @Override
@@ -969,15 +972,25 @@
         }
 
         if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
-                || mWakefulness == WAKEFULNESS_ASLEEP || mWakefulness == WAKEFULNESS_DOZING
                 || !mBootCompleted || !mSystemReady) {
             return false;
         }
 
         Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
         try {
+            if (eventTime > mLastInteractivePowerHintTime) {
+                powerHintInternal(POWER_HINT_INTERACTION, 0);
+                mLastInteractivePowerHintTime = eventTime;
+            }
+
             mNotifier.onUserActivity(event, uid);
 
+            if (mWakefulness == WAKEFULNESS_ASLEEP
+                    || mWakefulness == WAKEFULNESS_DOZING
+                    || (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
+                return false;
+            }
+
             if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
                 if (eventTime > mLastUserActivityTimeNoChangeLights
                         && eventTime > mLastUserActivityTime) {
@@ -2319,6 +2332,8 @@
             pw.println("  mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
             pw.println("  mLastUserActivityTimeNoChangeLights="
                     + TimeUtils.formatUptime(mLastUserActivityTimeNoChangeLights));
+            pw.println("  mLastInteractivePowerHintTime="
+                    + TimeUtils.formatUptime(mLastInteractivePowerHintTime));
             pw.println("  mDisplayReady=" + mDisplayReady);
             pw.println("  mHoldingWakeLockSuspendBlocker=" + mHoldingWakeLockSuspendBlocker);
             pw.println("  mHoldingDisplaySuspendBlocker=" + mHoldingDisplaySuspendBlocker);
@@ -2774,6 +2789,10 @@
             PowerManager.validateWakeLockParameters(flags, tag);
 
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
+            if ((flags & PowerManager.DOZE_WAKE_LOCK) != 0) {
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.DEVICE_POWER, null);
+            }
             if (ws != null && ws.size() != 0) {
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.UPDATE_DEVICE_STATS, null);
@@ -2859,7 +2878,10 @@
         public void userActivity(long eventTime, int event, int flags) {
             final long now = SystemClock.uptimeMillis();
             if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
-                    != PackageManager.PERMISSION_GRANTED) {
+                    != PackageManager.PERMISSION_GRANTED
+                    && mContext.checkCallingOrSelfPermission(
+                            android.Manifest.permission.USER_ACTIVITY)
+                            != PackageManager.PERMISSION_GRANTED) {
                 // Once upon a time applications could call userActivity().
                 // Now we require the DEVICE_POWER permission.  Log a warning and ignore the
                 // request instead of throwing a SecurityException so we don't break old apps.
@@ -2867,8 +2889,8 @@
                     if (now >= mLastWarningAboutUserActivityPermission + (5 * 60 * 1000)) {
                         mLastWarningAboutUserActivityPermission = now;
                         Slog.w(TAG, "Ignoring call to PowerManager.userActivity() because the "
-                                + "caller does not have DEVICE_POWER permission.  "
-                                + "Please fix your app!  "
+                                + "caller does not have DEVICE_POWER or USER_ACTIVITY "
+                                + "permission.  Please fix your app!  "
                                 + " pid=" + Binder.getCallingPid()
                                 + " uid=" + Binder.getCallingUid());
                     }
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 0523af7..4c080cb 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -16,16 +16,22 @@
 
 package com.android.server.trust;
 
+import android.app.AlarmManager;
+import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.PatternMatcher;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -43,6 +49,9 @@
  * TrustManager and the actual TrustAgent.
  */
 public class TrustAgentWrapper {
+    private static final String EXTRA_COMPONENT_NAME = "componentName";
+    private static final String TRUST_EXPIRED_ACTION = "android.server.trust.TRUST_EXPIRED_ACTION";
+    private static final String PERMISSION = "android.permission.PROVIDE_TRUST_AGENT";
     private static final boolean DEBUG = false;
     private static final String TAG = "TrustAgentWrapper";
 
@@ -79,6 +88,20 @@
     private boolean mTrustDisabledByDpm;
     private boolean mManagingTrust;
     private IBinder mSetTrustAgentFeaturesToken;
+    private AlarmManager mAlarmManager;
+    private final Intent mAlarmIntent;
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT_NAME);
+            if (TRUST_EXPIRED_ACTION.equals(intent.getAction())
+                    && mName.equals(component)) {
+                mHandler.removeMessages(MSG_TRUST_TIMEOUT);
+                mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
+            }
+        }
+    };
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -95,8 +118,10 @@
                     boolean initiatedByUser = msg.arg1 != 0;
                     long durationMs = msg.getData().getLong(DATA_DURATION);
                     if (durationMs > 0) {
-                        mHandler.removeMessages(MSG_TRUST_TIMEOUT);
-                        mHandler.sendEmptyMessageDelayed(MSG_TRUST_TIMEOUT, durationMs);
+                        long expiration = SystemClock.elapsedRealtime() + durationMs;
+                        PendingIntent op = PendingIntent.getBroadcast(mContext, 0, mAlarmIntent,
+                                PendingIntent.FLAG_CANCEL_CURRENT);
+                        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, expiration, op);
                     }
                     mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
                             (mMessage != null ? mMessage.toString() : null),
@@ -106,6 +131,7 @@
                 case MSG_TRUST_TIMEOUT:
                     if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
                     mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName);
+                    onTrustTimeout();
                     // Fall through.
                 case MSG_REVOKE_TRUST:
                     mTrusted = false;
@@ -212,8 +238,19 @@
             Intent intent, UserHandle user) {
         mContext = context;
         mTrustManagerService = trustManagerService;
+        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mUserId = user.getIdentifier();
         mName = intent.getComponent();
+
+        mAlarmIntent = new Intent(TRUST_EXPIRED_ACTION).putExtra(EXTRA_COMPONENT_NAME, mName);
+        mAlarmIntent.setData(Uri.parse(mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME)));
+
+        final IntentFilter alarmFilter = new IntentFilter(TRUST_EXPIRED_ACTION);
+        alarmFilter.addDataScheme(mAlarmIntent.getScheme());
+        final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME);
+        alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL);
+        mContext.registerReceiver(mBroadcastReceiver, alarmFilter);
+
         // Schedules a restart for when connecting times out. If the connection succeeds,
         // the restart is canceled in mCallback's onConnected.
         scheduleRestart();
@@ -227,6 +264,13 @@
         Slog.w(TAG , "Remote Exception", e);
     }
 
+    private void onTrustTimeout() {
+        try {
+            if (mTrustAgentService != null) mTrustAgentService.onTrustTimeout();
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
     /**
      * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
      */
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index de8b4fc..fc95e14 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -56,24 +56,34 @@
         return true;
     }
 
+    uint32_t matchedAxis = 0x0;
     const size_t N = mConfigs.size();
     for (size_t i = 0; i < N; i++) {
         const std::pair<ConfigDescription, uint32_t>& entry = mConfigs[i];
         uint32_t diff = entry.first.diff(config);
         if ((diff & entry.second) == 0) {
-            return true;
+            // Mark the axis that was matched.
+            matchedAxis |= entry.second;
         } else if ((diff & entry.second) == ResTable_config::CONFIG_LOCALE) {
             // If the locales differ, but the languages are the same and
             // the locale we are matching only has a language specified,
             // we match.
-            if (config.language[0] && memcmp(config.language, entry.first.language, sizeof(config.language)) == 0) {
+            if (config.language[0] &&
+                    memcmp(config.language, entry.first.language, sizeof(config.language)) == 0) {
                 if (config.country[0] == 0) {
-                    return true;
+                    matchedAxis |= ResTable_config::CONFIG_LOCALE;
                 }
             }
+        } else if ((diff & entry.second) == ResTable_config::CONFIG_SMALLEST_SCREEN_SIZE) {
+            // Special case if the smallest screen width doesn't match. We check that the
+            // config being matched has a smaller screen width than the filter specified.
+            if (config.smallestScreenWidthDp != 0 &&
+                    config.smallestScreenWidthDp < entry.first.smallestScreenWidthDp) {
+                matchedAxis |= ResTable_config::CONFIG_SMALLEST_SCREEN_SIZE;
+            }
         }
     }
-    return false;
+    return matchedAxis == (mConfigMask & mask);
 }
 
 status_t
diff --git a/tools/aapt/ResourceFilter.h b/tools/aapt/ResourceFilter.h
index f459584..d6430c0 100644
--- a/tools/aapt/ResourceFilter.h
+++ b/tools/aapt/ResourceFilter.h
@@ -24,8 +24,7 @@
 };
 
 /**
- * Implements logic for parsing and handling "-c" and "--preferred-configurations"
- * options.
+ * Implements logic for parsing and handling "-c" options.
  */
 class WeakResourceFilter : public ResourceFilter {
 public:
diff --git a/tools/aapt/tests/ResourceFilter_test.cpp b/tools/aapt/tests/ResourceFilter_test.cpp
index b55379e..bbc2e02 100644
--- a/tools/aapt/tests/ResourceFilter_test.cpp
+++ b/tools/aapt/tests/ResourceFilter_test.cpp
@@ -75,6 +75,17 @@
     EXPECT_TRUE(filter.match(config));
 }
 
+TEST(WeakResourceFilterTest, MatchesConfigWithOneMatchingAxis) {
+    WeakResourceFilter filter;
+    ASSERT_EQ(NO_ERROR, filter.parse(String8("fr_FR,sw360dp,normal,en_US")));
+
+    ConfigDescription config;
+    config.language[0] = 'e';
+    config.language[1] = 'n';
+
+    EXPECT_TRUE(filter.match(config));
+}
+
 TEST(WeakResourceFilterTest, DoesNotMatchConfigWithDifferentValueAxis) {
     WeakResourceFilter filter;
     ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
@@ -86,6 +97,32 @@
     EXPECT_FALSE(filter.match(config));
 }
 
+TEST(WeakResourceFilterTest, DoesNotMatchWhenOneQualifierIsExplicitlyNotMatched) {
+    WeakResourceFilter filter;
+    ASSERT_EQ(NO_ERROR, filter.parse(String8("fr_FR,en_US,normal,large,xxhdpi,sw320dp")));
+
+    ConfigDescription config;
+    config.language[0] = 'f';
+    config.language[1] = 'r';
+    config.smallestScreenWidthDp = 600;
+    config.version = 13;
+
+    EXPECT_FALSE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesSmallestWidthWhenSmaller) {
+    WeakResourceFilter filter;
+    ASSERT_EQ(NO_ERROR, filter.parse(String8("sw600dp")));
+
+    ConfigDescription config;
+    config.language[0] = 'f';
+    config.language[1] = 'r';
+    config.smallestScreenWidthDp = 320;
+    config.version = 13;
+
+    EXPECT_TRUE(filter.match(config));
+}
+
 TEST(WeakResourceFilterTest, MatchesConfigWithSameLanguageButNoRegionSpecified) {
     WeakResourceFilter filter;
     ASSERT_EQ(NO_ERROR, filter.parse(String8("de-rDE")));