Merge "Doze: Fast path for pickup pulses." into lmp-mr1-dev
diff --git a/Android.mk b/Android.mk
index ce72a85..39ddb55 100644
--- a/Android.mk
+++ b/Android.mk
@@ -69,6 +69,7 @@
 	core/java/android/app/IActivityPendingResult.aidl \
 	core/java/android/app/IAlarmManager.aidl \
 	core/java/android/app/IAppTask.aidl \
+	core/java/android/app/ITaskStackListener.aidl \
 	core/java/android/app/IBackupAgent.aidl \
 	core/java/android/app/IInstrumentationWatcher.aidl \
 	core/java/android/app/INotificationManager.aidl \
@@ -731,7 +732,8 @@
 # Whitelist of valid groups, used for default TOC grouping. Each sample must
 # belong to one (and only one) group. Assign samples to groups by setting
 # a sample.group var to one of these groups in the sample's _index.jd.
-sample_groups := -samplegroup Background \
+sample_groups := -samplegroup Admin \
+                 -samplegroup Background \
                  -samplegroup Connectivity \
                  -samplegroup Content \
                  -samplegroup Input \
diff --git a/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java
index c414f58..3ec63b4 100644
--- a/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java
+++ b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java
@@ -24,10 +24,12 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 
+import android.util.TimeUtils;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.os.BaseCommand;
 
 import java.io.PrintStream;
+import java.util.List;
 
 /**
  * This class is a command line utility for manipulating AppOps permissions.
@@ -40,15 +42,19 @@
 
     @Override
     public void onShowUsage(PrintStream out) {
-        out.println("usage: adb shell appops set <PACKAGE> <OP> "
-                + "<allow|ignore|deny|default> [--user <USER_ID>]\n"
+        out.println("usage: appops set [--user <USER_ID>] <PACKAGE> <OP> <MODE>\n"
+                + "       appops get [--user <USER_ID>] <PACKAGE> [<OP>]\n"
+                + "       appops reset [--user <USER_ID>] [<PACKAGE>]\n"
                 + "  <PACKAGE> an Android package name.\n"
                 + "  <OP>      an AppOps operation.\n"
+                + "  <MODE>    one of allow, ignore, deny, or default\n"
                 + "  <USER_ID> the user id under which the package is installed. If --user is not\n"
                 + "            specified, the current user is assumed.\n");
     }
 
     private static final String COMMAND_SET = "set";
+    private static final String COMMAND_GET = "get";
+    private static final String COMMAND_RESET = "reset";
 
     @Override
     public void onRun() throws Exception {
@@ -58,8 +64,17 @@
                 runSet();
                 break;
 
+            case COMMAND_GET:
+                runGet();
+                break;
+
+            case COMMAND_RESET:
+                runReset();
+                break;
+
             default:
-                throw new IllegalArgumentException("Unknown command '" + command + "'.");
+                System.err.println("Error: Unknown command: '" + command + "'.");
+                break;
         }
     }
 
@@ -71,6 +86,23 @@
     private static final String MODE_IGNORE = "ignore";
     private static final String MODE_DEFAULT = "default";
 
+    private int strOpToOp(String op) {
+        try {
+            return AppOpsManager.strOpToOp(op);
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            return Integer.parseInt(op);
+        } catch (NumberFormatException e) {
+        }
+        try {
+            return AppOpsManager.strDebugOpToOp(op);
+        } catch (IllegalArgumentException e) {
+            System.err.println("Error: " + e.getMessage());
+            return -1;
+        }
+    }
+
     private void runSet() throws Exception {
         String packageName = null;
         String op = null;
@@ -87,20 +119,27 @@
                 } else if (mode == null) {
                     mode = argument;
                 } else {
-                    throw new IllegalArgumentException("Unsupported argument: " + argument);
+                    System.err.println("Error: Unsupported argument: " + argument);
+                    return;
                 }
             }
         }
 
         if (packageName == null) {
-            throw new IllegalArgumentException("Package name not specified.");
+            System.err.println("Error: Package name not specified.");
+            return;
         } else if (op == null) {
-            throw new IllegalArgumentException("Operation not specified.");
+            System.err.println("Error: Operation not specified.");
+            return;
         } else if (mode == null) {
-            throw new IllegalArgumentException("Mode not specified.");
+            System.err.println("Error: Mode not specified.");
+            return;
         }
 
-        final int opInt = AppOpsManager.strOpToOp(op);
+        final int opInt = strOpToOp(op);
+        if (opInt < 0) {
+            return;
+        }
         final int modeInt;
         switch (mode) {
             case MODE_ALLOW:
@@ -116,7 +155,8 @@
                 modeInt = AppOpsManager.MODE_DEFAULT;
                 break;
             default:
-                throw new IllegalArgumentException("Mode is invalid.");
+                System.err.println("Error: Mode " + mode + " is not valid,");
+                return;
         }
 
         // Parsing complete, let's execute the command.
@@ -130,8 +170,155 @@
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
         final int uid = pm.getPackageUid(packageName, userId);
         if (uid < 0) {
-            throw new Exception("No UID for " + packageName + " for user " + userId);
+            System.err.println("Error: No UID for " + packageName + " in user " + userId);
+            return;
         }
         appOpsService.setMode(opInt, uid, packageName, modeInt);
     }
+
+    private void runGet() throws Exception {
+        String packageName = null;
+        String op = null;
+        int userId = UserHandle.USER_CURRENT;
+        for (String argument; (argument = nextArg()) != null;) {
+            if (ARGUMENT_USER.equals(argument)) {
+                userId = Integer.parseInt(nextArgRequired());
+            } else {
+                if (packageName == null) {
+                    packageName = argument;
+                } else if (op == null) {
+                    op = argument;
+                } else {
+                    System.err.println("Error: Unsupported argument: " + argument);
+                    return;
+                }
+            }
+        }
+
+        if (packageName == null) {
+            System.err.println("Error: Package name not specified.");
+            return;
+        }
+
+        final int opInt = op != null ? strOpToOp(op) : 0;
+
+        // Parsing complete, let's execute the command.
+
+        if (userId == UserHandle.USER_CURRENT) {
+            userId = ActivityManager.getCurrentUser();
+        }
+
+        final IPackageManager pm = ActivityThread.getPackageManager();
+        final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
+                ServiceManager.getService(Context.APP_OPS_SERVICE));
+        final int uid = pm.getPackageUid(packageName, userId);
+        if (uid < 0) {
+            System.err.println("Error: No UID for " + packageName + " in user " + userId);
+            return;
+        }
+        List<AppOpsManager.PackageOps> ops = appOpsService.getOpsForPackage(uid, packageName,
+                op != null ? new int[] {opInt} : null);
+        if (ops == null || ops.size() <= 0) {
+            System.out.println("No operations.");
+            return;
+        }
+        final long now = System.currentTimeMillis();
+        for (int i=0; i<ops.size(); i++) {
+            List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
+            for (int j=0; j<entries.size(); j++) {
+                AppOpsManager.OpEntry ent = entries.get(j);
+                System.out.print(AppOpsManager.opToName(ent.getOp()));
+                System.out.print(": ");
+                switch (ent.getMode()) {
+                    case AppOpsManager.MODE_ALLOWED:
+                        System.out.print("allow");
+                        break;
+                    case AppOpsManager.MODE_IGNORED:
+                        System.out.print("ignore");
+                        break;
+                    case AppOpsManager.MODE_ERRORED:
+                        System.out.print("deny");
+                        break;
+                    case AppOpsManager.MODE_DEFAULT:
+                        System.out.print("default");
+                        break;
+                    default:
+                        System.out.print("mode=");
+                        System.out.print(ent.getMode());
+                        break;
+                }
+                if (ent.getTime() != 0) {
+                    System.out.print("; time=");
+                    StringBuilder sb = new StringBuilder();
+                    TimeUtils.formatDuration(now - ent.getTime(), sb);
+                    System.out.print(sb);
+                    System.out.print(" ago");
+                }
+                if (ent.getRejectTime() != 0) {
+                    System.out.print("; rejectTime=");
+                    StringBuilder sb = new StringBuilder();
+                    TimeUtils.formatDuration(now - ent.getRejectTime(), sb);
+                    System.out.print(sb);
+                    System.out.print(" ago");
+                }
+                if (ent.getDuration() == -1) {
+                    System.out.print(" (running)");
+                } else if (ent.getDuration() != 0) {
+                    System.out.print("; duration=");
+                    StringBuilder sb = new StringBuilder();
+                    TimeUtils.formatDuration(ent.getDuration(), sb);
+                    System.out.print(sb);
+                }
+                System.out.println();
+            }
+        }
+    }
+
+    private void runReset() throws Exception {
+        String packageName = null;
+        int userId = UserHandle.USER_CURRENT;
+        for (String argument; (argument = nextArg()) != null;) {
+            if (ARGUMENT_USER.equals(argument)) {
+                String userStr = nextArgRequired();
+                if ("all".equals(userStr)) {
+                    userId = UserHandle.USER_ALL;
+                } else if ("current".equals(userStr)) {
+                    userId = UserHandle.USER_CURRENT;
+                } else if ("owner".equals(userStr)) {
+                    userId = UserHandle.USER_OWNER;
+                } else {
+                    userId = Integer.parseInt(nextArgRequired());
+                }
+            } else {
+                if (packageName == null) {
+                    packageName = argument;
+                } else {
+                    System.err.println("Error: Unsupported argument: " + argument);
+                    return;
+                }
+            }
+        }
+
+        // Parsing complete, let's execute the command.
+
+        if (userId == UserHandle.USER_CURRENT) {
+            userId = ActivityManager.getCurrentUser();
+        }
+
+        final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
+                ServiceManager.getService(Context.APP_OPS_SERVICE));
+        appOpsService.resetAllModes(userId, packageName);
+        System.out.print("Reset all modes for: ");
+        if (userId == UserHandle.USER_ALL) {
+            System.out.print("all users");
+        } else {
+            System.out.print("user "); System.out.print(userId);
+        }
+        System.out.print(", ");
+        if (packageName == null) {
+            System.out.println("all packages");
+        } else {
+            System.out.print("package "); System.out.println(packageName);
+        }
+    }
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6ec48e5..06a26ec 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -774,6 +774,14 @@
             return true;
         }
 
+        case REGISTER_TASK_STACK_LISTENER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            registerTaskStackListener(ITaskStackListener.Stub.asInterface(token));
+            reply.writeNoException();
+            return true;
+        }
+
         case GET_TASK_FOR_ACTIVITY_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -3266,6 +3274,18 @@
         data.recycle();
         reply.recycle();
     }
+    @Override
+    public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(listener.asBinder());
+        mRemote.transact(REGISTER_TASK_STACK_LISTENER_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException
     {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ba9c9d6..95870cf9 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -26,6 +26,7 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.ArrayMap;
 
@@ -734,6 +735,18 @@
     }
 
     /**
+     * @hide
+     */
+    public static int strDebugOpToOp(String op) {
+        for (int i=0; i<sOpNames.length; i++) {
+            if (sOpNames[i].equals(op)) {
+                return i;
+            }
+        }
+        throw new IllegalArgumentException("Unknown operation string: " + op);
+    }
+
+    /**
      * Retrieve the permission associated with an operation, or null if there is not one.
      * @hide
      */
@@ -996,7 +1009,7 @@
     /** @hide */
     public void resetAllModes() {
         try {
-            mService.resetAllModes();
+            mService.resetAllModes(UserHandle.myUserId(), null);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 5362303..1ccbd27 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -139,6 +139,7 @@
     public StackInfo getStackInfo(int stackId) throws RemoteException;
     public boolean isInHomeStack(int taskId) throws RemoteException;
     public void setFocusedStack(int stackId) throws RemoteException;
+    public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException;
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
     public ContentProviderHolder getContentProvider(IApplicationThread caller,
             String name, int userId, boolean stable) throws RemoteException;
@@ -788,4 +789,5 @@
     int LAUNCH_ASSIST_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+239;
     int START_IN_PLACE_ANIMATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+240;
     int CHECK_PERMISSION_WITH_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+241;
+    int REGISTER_TASK_STACK_LISTENER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+242;
 }
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
new file mode 100644
index 0000000..4b0935c
--- /dev/null
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -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.
+ */
+
+package android.app;
+
+/** @hide */
+oneway interface ITaskStackListener {
+    void onTaskStackChanged();
+}
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 78b9c18..f6b6978 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -291,16 +291,16 @@
     /**
      * Sets the underlying networks used by the VPN for its upstream connections.
      *
-     * Used by the system to know the actual networks that carry traffic for apps affected by this
-     * VPN in order to present this information to the user (e.g., via status bar icons).
+     * <p>Used by the system to know the actual networks that carry traffic for apps affected by
+     * this VPN in order to present this information to the user (e.g., via status bar icons).
      *
-     * This method only needs to be called if the VPN has explicitly bound its underlying
+     * <p>This method only needs to be called if the VPN has explicitly bound its underlying
      * communications channels &mdash; such as the socket(s) passed to {@link #protect(int)} &mdash;
      * to a {@code Network} using APIs such as {@link Network#bindSocket(Socket)} or
      * {@link Network#bindSocket(DatagramSocket)}. The VPN should call this method every time
      * the set of {@code Network}s it is using changes.
      *
-     * {@code networks} is one of the following:
+     * <p>{@code networks} is one of the following:
      * <ul>
      * <li><strong>a non-empty array</strong>: an array of one or more {@link Network}s, in
      * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular)
@@ -310,11 +310,11 @@
      * underlying network connection, and thus, app traffic will not be sent or received.</li>
      * <li><strong>null</strong>: (default) signifies that the VPN uses whatever is the system's
      * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket}
-     * APIs mentioned above to send traffic over specific channels.
+     * APIs mentioned above to send traffic over specific channels.</li>
      * </ul>
      *
-     * This call will succeed only if the VPN is currently established. For setting this value when
-     * the VPN has not yet been established, see {@link Builder#setUnderlyingNetworks}.
+     * <p>This call will succeed only if the VPN is currently established. For setting this value
+     * when the VPN has not yet been established, see {@link Builder#setUnderlyingNetworks}.
      *
      * @param networks An array of networks the VPN uses to tunnel traffic to/from its servers.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5e5fbc7..0c036d51 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6608,6 +6608,14 @@
         public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
 
         /**
+         * Global override to disable VoLTE (independent of user setting)
+         * <p>
+         * Type: int (1 for disable VoLTE, 0 to use user configuration)
+         * @hide
+         */
+        public static final String VOLTE_FEATURE_DISABLED = "volte_feature_disabled";
+
+        /**
          * Whether user can enable/disable LTE as a preferred network. A carrier might control
          * this via gservices, OMA-DM, carrier app, etc.
          * <p>
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index a52dd48..99bf9f3 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -36,7 +36,7 @@
     List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
     List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
     void setMode(int code, int uid, String packageName, int mode);
-    void resetAllModes();
+    void resetAllModes(int reqUserId, String reqPackageName);
     int checkAudioOperation(int code, int usage, int uid, String packageName);
     void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages);
 
diff --git a/docs/html/samples/admin.jd b/docs/html/samples/admin.jd
new file mode 100644
index 0000000..c6637d8
--- /dev/null
+++ b/docs/html/samples/admin.jd
@@ -0,0 +1,11 @@
+page.title=Admin
+@jd:body
+
+
+<div id="samples" class="admin">
+</div>
+
+
+<script>
+  $(document).ready(showSamples);
+</script>
diff --git a/docs/html/samples/new/index.jd b/docs/html/samples/new/index.jd
index ba75072..279b910 100644
--- a/docs/html/samples/new/index.jd
+++ b/docs/html/samples/new/index.jd
@@ -2,19 +2,18 @@
 
 @jd:body
 
-<p>The following code samples were recently published for the L Developer Preview. You can
+<p>The following code samples were recently published. You can
 download them in the Android SDK Manager under the <b>SDK Samples</b> component
-for the L Developer Preview.</p>
+for API 21.</p>
 
 <p class="note">
-  <strong>Note:</strong> At this time, the downloadable projects are designed
+  <strong>Note:</strong> The downloadable projects are designed
    for use with Gradle and Android Studio.
 </p>
 
-
 <!-- NOTE TO EDITORS: add most recent samples first -->
 
-<h3 id="MediaBrowserService">Media Browser Service</h3>
+<h3 id="MediaBrowserService"><a href="/samples/MediaBrowserService/index.html">Media Browser Service</a></h3>
 
 <p>
 This sample is a simple audio media app that exposes its media
@@ -29,10 +28,8 @@
   href="http://android.com/auto">Android Auto</a>.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-MediaBrowserService">Get it on GitHub</a></p>
 
-
-<h3 id="MessagingService">Messaging Service</h3>
+<h3 id="MessagingService"><a href="/samples/MessagingService/index.html">Messaging Service</a></h3>
 
 <p>
 This sample shows a simple service that sends notifications using
@@ -46,10 +43,8 @@
   href="http://android.com/auto">Android Auto</a>.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-MessagingService">Get it on GitHub</a></p>
 
-
-<h3 id="SpeedTracker">Speed Tracker (Wear)</h3>
+<h3 id="SpeedTracker"><a href="/samples/SpeedTracker/index.html">Speed Tracker (Wear)</a></h3>
 
 <p>
 This sample uses the FusedLocation APIs of Google Play Services on Android Wear 
@@ -62,10 +57,8 @@
 made of those coordinates on a map on the phone.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-SpeedTracker">Get it on GitHub</a></p>
 
-
-<h3 id="AppRestrictionSchema">AppRestrictionSchema</h3>
+<h3 id="AppRestrictionSchema"><a href="/samples/AppRestrictionSchema/index.html">AppRestrictionSchema</a></h3>
 
 <p>
 This sample shows how to use app restrictions. This application has one boolean
@@ -74,29 +67,23 @@
 AppRestrictionEnforcer sample to toggle the restriction.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-AppRestrictionSchema">Get it on GitHub</a></p>
 
-
-<h3 id="AppRestrictionEnforcer">AppRestrictionEnforcer</h3>
+<h3 id="AppRestrictionEnforcer"><a href="/samples/AppRestrictionEnforcer/index.html">AppRestrictionEnforcer</a></h3>
 
 <p>
 This sample demonstrates how to set restrictions to other apps as a profile owner.
 Use AppRestrictionSchema sample as a app with available restrictions.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-AppRestrictionEnforcer">Get it on GitHub</a></p>
 
-
-<h3 id="DocumentCentricRelinquishIdentity">DocumentCentricRelinquishIdentity</h3>
+<h3 id="DocumentCentricRelinquishIdentity"><a href="/samples/DocumentCentricRelinquishIdentity/index.html">DocumentCentricRelinquishIdentity</a></h3>
 
 <p>
 This sample shows how to relinquish identity to activities above it in the task stack.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-DocumentCentricRelinquishIdentity">Get it on GitHub</a></p>
 
-
-<h3 id="DocumentCentricApps">DocumentCentricApps</h3>
+<h3 id="DocumentCentricApps"><a href="/samples/DocumentCentricApps/index.html">DocumentCentricApps</a></h3>
 
 <p>
 This sample shows the basic usage of the new "Document Centric Apps" API.
@@ -105,10 +92,8 @@
 created for every new document in the overview menu.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-DocumentCentricApps">Get it on GitHub</a></p>
 
-
-<h3 id="HdrViewfinder">HdrViewfinder</h3>
+<h3 id="HdrViewfinder"><a href="/samples/HdrViewfinder/index.html">HdrViewfinder</a></h3>
 
 <p>
 This demo implements a real-time high-dynamic-range camera viewfinder, by alternating
@@ -116,10 +101,8 @@
 compositing together the latest two frames whenever a new frame is captured.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-HdrViewfinder">Get it on GitHub</a></p>
 
-
-<h3 id="Interpolator">Interpolator</h3>
+<h3 id="Interpolator"><a href="/samples/Interpolator/index.html">Interpolator</a></h3>
 
 <p>
 This sample demonstrates the use of animation interpolators and path animations for
@@ -127,10 +110,8 @@
 view (scale X and Y) along a path.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-Interpolator">Get it on GitHub</a></p>
 
-
-<h3 id="DrawableTinting">DrawableTinting</h3>
+<h3 id="DrawableTinting"><a href="/samples/DrawableTinting/index.html">DrawableTinting</a></h3>
 
 <p>Sample that shows applying tinting and color filters to Drawables both programmatically
 and as Drawable resources in XML.</p>
@@ -141,54 +122,43 @@
 with a reference to a color and a PorterDuff blend mode. The color and blend mode can be
 changed from the UI to see the effect of different options.</p>
 
-<p><a href="http://github.com/googlesamples/android-DrawableTinting">Get it on GitHub</a></p>
 
-
-<h3 id="LNotifications">LNotifications</h3>
+<h3 id="LNotifications"><a href="/samples/LNotifications/index.html">LNotifications</a></h3>
 
 <p>
 This sample demonstrates how new features for notifications introduced in Android 5.0
 are used such as Heads-Up notifications, visibility, people, category and priority
 metadata. </p>
-<p><a href="http://github.com/googlesamples/android-LNotifications">Get it on GitHub</a></p>
 
 
-<h3 id="CardView">CardView</h3>
+<h3 id="CardView"><a href="/samples/CardView/index.html">CardView</a></h3>
 
 <p>
 This sample demonstrates how to use the CardView UI widget introduced in Android 5.0, using the support library for backward compatibility.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-CardView">Get it on GitHub</a></p>
 
-
-<h3 id="RecyclerView">RecyclerView</h3>
+<h3 id="RecyclerView"><a href="/samples/RecyclerView/index.html">RecyclerView</a></h3>
 
 <p>
 Demonstration of using RecyclerView with a LayoutManager to create a vertical ListView.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-RecyclerView">Get it on GitHub</a></p>
 
-
-<h3 id="RevealEffectBasic">RevealEffectBasic</h3>
+<h3 id="RevealEffectBasic"><a href="/samples/RevealEffectBasic/index.html">RevealEffectBasic</a></h3>
 
 <p>
 A sample demonstrating how to perform a reveal effect for UI elements within the Material Design framework.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-RevealEffectBasic">Get it on GitHub</a></p>
 
-
-<h3 id="FloatingActionButtonBasic">FloatingActionButtonBasic</h3>
+<h3 id="FloatingActionButtonBasic"><a href="/samples/FloatingActionButtonBasic/index.html">FloatingActionButtonBasic</a></h3>
 
 <p>
 This sample shows the two sizes of Floating Action Buttons and how to interact with
 them.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-FloatingActionButtonBasic">Get it on GitHub</a></p>
-
 
 <!--
 <h3 id="">SampleName</h3>
@@ -205,36 +175,15 @@
 </p>
 -->
 
-
-<h3 id="NavigationDrawerSample">NavigationDrawerSample</h3>
-<!--
-<div class="figure" style="width:220px">
-  <img src="" srcset="@2x.png 2x" alt="" height="375" />
-  <p class="img-caption">
-    <strong>Figure n.</strong> Single sentence summarizing the figure.
-  </p>
-</div>
--->
-
-<p>
-This sample illustrates a common usage of the Android support library's
-{@link android.support.v4.widget.DrawerLayout} widget.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-NavigationDrawer">Get it on GitHub</a></p>
-
-
-<h3 id="JobSchedulerSample">JobSchedulerSample</h3>
+<h3 id="JobSchedulerSample"><a href="/samples/JobScheduler/index.html">JobScheduler</a></h3>
 
 <p>
 This sample app allows the user to schedule jobs through the UI, and shows
 visual cues when the jobs are executed.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-JobScheduler">Get it on GitHub</a></p>
 
-
-<h3 id="AndroidTVLeanbackSample">AndroidTVLeanbackSample</h3>
+<h3 id="AndroidTVLeanbackSample"><a href="https://github.com/googlesamples/androidtv-leanback">AndroidTVLeanbackSample</a></h3>
 <!--
 <div class="figure" style="width:220px">
   <img src="" srcset="@2x.png 2x" alt="" height="375" />
@@ -248,10 +197,7 @@
 This sample demonstrates use of the Android TV Leanback Support Library.
 </p>
 
-<p><a href="http://github.com/googlesamples/androidtv-Leanback">Get it on GitHub</a></p>
-
-
-<h3 id="Visual-Game-Controller">Visual-Game-Controller</h3>
+<h3 id="Visual-Game-Controller"><a href="https://github.com/googlesamples/androidtv-VisualGameController">Visual-Game-Controller</a></h3>
 <!--
 <div class="figure" style="width:220px">
   <img src="" srcset="@2x.png 2x" alt="" height="375" />
@@ -265,10 +211,8 @@
 This sample displays events received from a game controller shown on the screen.
 </p>
 
-<p><a href="http://github.com/googlesamples/androidtv-VisualGameController">Get it on GitHub</a></p>
 
-
-<h3 id="GameControllerSample">GameControllerSample</h3>
+<h3 id="GameControllerSample"><a href="https://github.com/googlesamples/androidtv-GameController/">GameControllerSample</a></h3>
 <!--
 <div class="figure" style="width:220px">
   <img src="" srcset="@2x.png 2x" alt="" height="375" />
@@ -283,10 +227,8 @@
 handling.
 </p>
 
-<p><a href="http://github.com/googlesamples/androidtv-GameController">Get it on GitHub</a></p>
 
-
-<h3 id="ClippingBasic">ClippingBasic</h3>
+<h3 id="ClippingBasic"><a href="/samples/ClippingBasic/index.html">ClippingBasic</a></h3>
 <!--
 <div class="figure" style="width:220px">
   <img src="" srcset="@2x.png 2x" alt="" height="375" />
@@ -300,19 +242,17 @@
 This sample demonstrates clipping on a {@link android.view.View}.
 </p>
 
-<p><a href="http://github.com/googlesamples/android-ClippingBasic">Get it on GitHub</a></p>
-
 <div class="figure" style="width:220px">
   <img src="{@docRoot}samples/images/JobSchedulerSample.png"
       srcset="{@docRoot}samples/images/JobSchedulerSample@2x.png 2x"
       alt="" height="375" />
   <p class="img-caption">
-    <strong>Figure 3.</strong> The JobSchedulerSample sample app.
+    <strong>Figure 1.</strong> The JobSchedulerSample sample app.
   </p>
 </div>
 
 
-<h3 id="ElevationDrag">ElevationDrag</h3>
+<h3 id="ElevationDrag"><a href="/samples/ElevationDrag/index.html">ElevationDrag</a></h3>
 <!--
 <div class="figure" style="width:220px">
   <img src="" srcset="@2x.png 2x" alt="" height="375" />
@@ -326,10 +266,8 @@
 Elevation and z-translation are used to render the shadows. The views are
 clipped using different outlines.</p>
 
-<p><a href="http://github.com/googlesamples/android-ElevationDrag">Get it on GitHub</a></p>
 
-
-<h3 id="ElevationBasic">ElevationBasic</h3>
+<h3 id="ElevationBasic"><a href="/samples/ElevationBasic/index.html">ElevationBasic</a></h3>
 <!--
 <div class="figure" style="width:220px">
 <img src="" srcset="@2x.png 2x" alt="" height="375" />
@@ -348,10 +286,8 @@
       <code>setTranslationZ()</code>.</li>
 </ul>
 
-<p><a href="http://github.com/googlesamples/android-ElevationBasic">Get it on GitHub</a></p>
 
-
-<h3 id="ActivitySceneTransitionBasic">ActivitySceneTransitionBasic</h3>
+<h3 id="ActivitySceneTransitionBasic"><a href="/samples/ActivitySceneTransitionBasic/index.html">ActivitySceneTransitionBasic</a></h3>
 <div class="figure" style="width:220px">
   <img src="{@docRoot}samples/images/ActivitySceneTransitionBasic.png"
       srcset="{@docRoot}samples/images/ActivitySceneTransitionBasic@2x.png 2x"
@@ -366,10 +302,8 @@
 of <code>moveImage</code> and <code>changeBounds</code> to nicely transition
 from a grid of images to an activity with a large image and detail text. </p>
 
-<p><a href="http://github.com/googlesamples/android-ActivitySceneTransition">Get it on GitHub</a></p>
 
-
-<h3 id="Camera2Video">Camera2Video</h3>
+<h3 id="Camera2Video"><a href="/samples/Camera2Video/index.html">Camera2Video</a></h3>
 <!--
 <div class="figure" style="width:220px">
 <img src="" srcset="@2x.png 2x" alt="" height="375" />
@@ -381,10 +315,8 @@
 
 <p>This sample demonstrates how to record video using the Camera2 API.</p>
 
-<p><a href="http://github.com/googlesamples/android-Camera2Video">Get it on GitHub</a></p>
 
-
-<h3 id="Camera2Basic">Camera2Basic</h3>
+<h3 id="Camera2Basic"><a href="/samples/Camera2Basic/index.html">Camera2Basic</a></h3>
 
 <!--
 <div class="figure" style="width:220px">
@@ -398,16 +330,14 @@
 <p>This sample demonstrates the basic use of the Camera2 API. The sample code
 demonstrates how you can display camera preview and take pictures.</p>
 
-<p><a href="http://github.com/googlesamples/android-Camera2Basic">Get it on GitHub</a></p>
 
-
-<h3 id="BasicManagedProfile">BasicManagedProfile</h3>
+<h3 id="BasicManagedProfile"><a href="/samples/BasicManagedProfile/index.html">BasicManagedProfile</a></h3>
 <div class="figure" style="width:220px">
   <img src="{@docRoot}samples/images/BasicManagedProfile.png"
      srcset="{@docRoot}samples/images/BasicManagedProfile@2x.png 2x"
      alt="" height="375" />
   <p class="img-caption">
-    <strong>Figure 1.</strong> The BasicManagedProfile sample app.
+    <strong>Figure 3.</strong> The BasicManagedProfile sample app.
   </p>
 </div>
 
@@ -422,5 +352,3 @@
 <p class="note"><strong>Note:</strong> There can be only one managed profile on
   a device at a time.</p>
 
-<p><a href="http://github.com/googlesamples/android-BasicManagedProfile">Get it on GitHub</a></p>
-
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index c524edc..6bad652 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -47,6 +47,10 @@
         ViewGroupAdapterBridge.link(this, mAdapter);
     }
 
+    public void refreshAdapter() {
+        mAdapter.refresh();
+    }
+
     public static class Adapter extends UserSwitcherController.BaseUserAdapter
             implements OnClickListener {
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 29f291d..4f0700e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
+import android.app.ITaskStackListener;
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ActivityNotFoundException;
@@ -56,6 +57,7 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+
 /** A proxy implementation for the recents component */
 public class AlternateRecentsComponent implements ActivityOptions.OnAnimationStartedListener {
 
@@ -79,6 +81,28 @@
     final static String sRecentsPackage = "com.android.systemui";
     final static String sRecentsActivity = "com.android.systemui.recents.RecentsActivity";
 
+    /**
+     * An implementation of ITaskStackListener, that allows us to listen for changes to the system
+     * task stacks and update recents accordingly.
+     */
+    class TaskStackListenerImpl extends ITaskStackListener.Stub {
+        @Override
+        public void onTaskStackChanged() {
+            RecentsConfiguration config = RecentsConfiguration.getInstance();
+            if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
+                // Load the next task only if we aren't svelte
+                RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+                RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
+                loader.preloadTasks(plan, true /* isTopTaskHome */);
+                RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+                launchOpts.numVisibleTasks = 1;
+                launchOpts.numVisibleTaskThumbnails = 1;
+                launchOpts.onlyLoadForCache = true;
+                loader.loadTasks(mContext, plan, launchOpts);
+            }
+        }
+    }
+
     static RecentsComponent.Callbacks sRecentsComponentCallbacks;
     static RecentsTaskLoadPlan sInstanceLoadPlan;
 
@@ -86,6 +110,7 @@
     LayoutInflater mInflater;
     SystemServicesProxy mSystemServicesProxy;
     Handler mHandler;
+    TaskStackListenerImpl mTaskStackListener;
     boolean mBootCompleted;
     boolean mStartAnimationTriggered;
     boolean mCanReuseTaskStackViews = true;
@@ -116,6 +141,10 @@
         mSystemServicesProxy = new SystemServicesProxy(context);
         mHandler = new Handler();
         mTaskStackBounds = new Rect();
+
+        // Register the task stack listener
+        mTaskStackListener = new TaskStackListenerImpl();
+        mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
     }
 
     public void onStart() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 6dc2edb..a37bc54 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -167,10 +167,6 @@
             if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 // When the screen turns off, dismiss Recents to Home
                 dismissRecentsToHome(false);
-                // Preload the metadata for all tasks in the background
-                RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-                RecentsTaskLoadPlan plan = loader.createLoadPlan(context);
-                loader.preloadTasks(plan, true /* isTopTaskHome */);
             } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) {
                 // When the search activity changes, update the Search widget
                 refreshSearchWidget();
@@ -437,22 +433,6 @@
             onEnterAnimationTriggered();
         }
 
-        // Start listening for widget package changes if there is one bound, post it since we don't
-        // want it stalling the startup
-        if (mConfig.searchBarAppWidgetId >= 0) {
-            final WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks> callback =
-                    new WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks>(this);
-            mRecentsView.post(new Runnable() {
-                @Override
-                public void run() {
-                    RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks cb = callback.get();
-                    if (cb != null) {
-                        mAppWidgetHost.startListening(cb);
-                    }
-                }
-            });
-        }
-
         mStatusBar = ((SystemUIApplication) getApplication())
                 .getComponent(PhoneStatusBar.class);
     }
@@ -539,15 +519,29 @@
         unregisterReceiver(mSystemBroadcastReceiver);
 
         // Stop listening for widget package changes if there was one bound
-        if (mAppWidgetHost.isListening()) {
-            mAppWidgetHost.stopListening();
-        }
+        mAppWidgetHost.stopListening();
     }
 
     public void onEnterAnimationTriggered() {
         // Try and start the enter animation (or restart it on configuration changed)
         ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
-        mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t));
+        ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t);
+        mRecentsView.startEnterRecentsAnimation(ctx);
+        if (mConfig.searchBarAppWidgetId >= 0) {
+            final WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks> cbRef =
+                    new WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks>(
+                            RecentsActivity.this);
+            ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+                @Override
+                public void run() {
+                    // Start listening for widget package changes if there is one bound
+                    RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks cb = cbRef.get();
+                    if (cb != null) {
+                        mAppWidgetHost.startListening(cb);
+                    }
+                }
+            });
+        }
 
         // Animate the SystemUI scrim views
         mScrimViews.startEnterRecentsAnimation();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
index a63e167..5bae37a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
@@ -43,23 +43,23 @@
 
     public void startListening(RecentsAppWidgetHostCallbacks cb) {
         mCb = cb;
-        mIsListening = true;
-        super.startListening();
+        if (!mIsListening) {
+            mIsListening = true;
+            super.startListening();
+        }
     }
 
     @Override
     public void stopListening() {
-        super.stopListening();
+        if (mIsListening) {
+            super.stopListening();
+        }
         // Ensure that we release any references to the callbacks
         mCb = null;
         mContext = null;
         mIsListening = false;
     }
 
-    public boolean isListening() {
-        return mIsListening;
-    }
-
     @Override
     protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) {
         if (mCb == null) return;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 9a4bd08..3fbd5a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -21,6 +21,7 @@
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
+import android.app.ITaskStackListener;
 import android.app.SearchManager;
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
@@ -536,4 +537,15 @@
             e.printStackTrace();
         }
     }
+
+    /** Registers a task stack listener with the system. */
+    public void registerTaskStackListener(ITaskStackListener listener) {
+        if (mIam == null) return;
+
+        try {
+            mIam.registerTaskStackListener(listener);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 46a5d8d..746a7df 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -204,6 +204,10 @@
 
     /** Requests all task stacks to start their enter-recents animation */
     public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
+        // We have to increment/decrement the post animation trigger in case there are no children
+        // to ensure that it runs
+        ctx.postAnimationTrigger.increment();
+
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -212,6 +216,7 @@
                 stackView.startEnterRecentsAnimation(ctx);
             }
         }
+        ctx.postAnimationTrigger.decrement();
     }
 
     /** Requests all task stacks to start their exit-recents animation */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
index 4586f12..e1d80fd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
@@ -27,7 +27,7 @@
     public static class TaskViewEnterContext {
         // A trigger to run some logic when all the animations complete.  This works around the fact
         // that it is difficult to coordinate ViewPropertyAnimators
-        ReferenceCountedTrigger postAnimationTrigger;
+        public ReferenceCountedTrigger postAnimationTrigger;
         // An update listener to notify as the enter animation progresses (used for the home transition)
         ValueAnimator.AnimatorUpdateListener updateListener;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 7ee1fc5..1460e5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -107,6 +107,7 @@
     public void show(boolean animate) {
         if (mUserSwitcher != null && mUserSwitcherContainer.getVisibility() != View.VISIBLE) {
             cancelAnimations();
+            mAdapter.refresh();
             mUserSwitcherContainer.setVisibility(View.VISIBLE);
             mStatusBarView.setKeyguardUserSwitcherShowing(true, animate);
             if (animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index e5b357a..4ac41a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -417,18 +417,6 @@
             }
         }
 
-        public int getSwitchableUsers() {
-            int result = 0;
-            ArrayList<UserRecord> users = mController.mUsers;
-            int N = users.size();
-            for (int i = 0; i < N; i++) {
-                if (users.get(i).info != null) {
-                    result++;
-                }
-            }
-            return result;
-        }
-
         public Drawable getDrawable(Context context, UserRecord item) {
             if (item.isAddUser) {
                 return context.getDrawable(R.drawable.ic_add_circle_qs);
@@ -436,6 +424,10 @@
             return UserIcons.getDefaultUserIcon(item.isGuest ? UserHandle.USER_NULL : item.info.id,
                     /* light= */ true);
         }
+
+        public void refresh() {
+            mController.refreshUsers(UserHandle.USER_NULL);
+        }
     }
 
     public static final class UserRecord {
@@ -500,6 +492,7 @@
             } else {
                 v = (UserDetailView) convertView;
             }
+            v.refreshAdapter();
             return v;
         }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ca0d481..8b53a62 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -4055,12 +4055,12 @@
                     mAppsToBeHidden.remove(appToken);
                     mAppsThatDismissKeyguard.remove(appToken);
                     if (mAppsToBeHidden.isEmpty()) {
-                        if (mKeyguardSecureIncludingHidden) {
+                        if (dismissKeyguard && !mKeyguardSecure) {
+                            mAppsThatDismissKeyguard.add(appToken);
+                        } else {
                             mWinShowWhenLocked = win;
                             mHideLockScreen = true;
                             mForceStatusBarFromKeyguard = false;
-                        } else if (dismissKeyguard && !mKeyguardSecure) {
-                            mAppsThatDismissKeyguard.add(appToken);
                         }
                     }
                 } else if (dismissKeyguard) {
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index c3465d1..42a5195 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -29,6 +29,7 @@
 import java.util.List;
 import java.util.Map;
 
+import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
 import android.content.Context;
@@ -53,7 +54,6 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 
@@ -78,10 +78,12 @@
     final Handler mHandler;
 
     boolean mWriteScheduled;
+    boolean mFastWriteScheduled;
     final Runnable mWriteRunner = new Runnable() {
         public void run() {
             synchronized (AppOpsService.this) {
                 mWriteScheduled = false;
+                mFastWriteScheduled = false;
                 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
                     @Override protected Void doInBackground(Void... params) {
                         writeState();
@@ -237,7 +239,7 @@
                 }
             }
             if (changed) {
-                scheduleWriteLocked();
+                scheduleFastWriteLocked();
             }
         }
     }
@@ -250,7 +252,7 @@
                     if (pkgs.size() <= 0) {
                         mUidOps.remove(uid);
                     }
-                    scheduleWriteLocked();
+                    scheduleFastWriteLocked();
                 }
             }
         }
@@ -260,7 +262,7 @@
         synchronized (this) {
             if (mUidOps.indexOfKey(uid) >= 0) {
                 mUidOps.remove(uid);
-                scheduleWriteLocked();
+                scheduleFastWriteLocked();
             }
         }
     }
@@ -400,7 +402,7 @@
                         // if there is nothing else interesting in it.
                         pruneOp(op, uid, packageName);
                     }
-                    scheduleWriteNowLocked();
+                    scheduleFastWriteLocked();
                 }
             }
         }
@@ -436,16 +438,20 @@
     }
 
     @Override
-    public void resetAllModes() {
-        int callingUid = Binder.getCallingUid();
+    public void resetAllModes(int reqUserId, String reqPackageName) {
+        final int callingPid = Binder.getCallingPid();
+        final int callingUid = Binder.getCallingUid();
         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
-                Binder.getCallingPid(), callingUid, null);
+                callingPid, callingUid, null);
+        reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
+                true, true, "resetAllModes", null);
         HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null;
         synchronized (this) {
             boolean changed = false;
             for (int i=mUidOps.size()-1; i>=0; i--) {
                 HashMap<String, Ops> packages = mUidOps.valueAt(i);
-                if (UserHandle.getUserId(callingUid) != UserHandle.getUserId(mUidOps.keyAt(i))) {
+                if (reqUserId != UserHandle.USER_ALL
+                        && reqUserId != UserHandle.getUserId(mUidOps.keyAt(i))) {
                     // Skip any ops for a different user
                     continue;
                 }
@@ -453,6 +459,10 @@
                 while (it.hasNext()) {
                     Map.Entry<String, Ops> ent = it.next();
                     String packageName = ent.getKey();
+                    if (reqPackageName != null && !reqPackageName.equals(packageName)) {
+                        // Skip any ops for a different package
+                        continue;
+                    }
                     Ops pkgOps = ent.getValue();
                     for (int j=pkgOps.size()-1; j>=0; j--) {
                         Op curOp = pkgOps.valueAt(j);
@@ -478,7 +488,7 @@
                 }
             }
             if (changed) {
-                scheduleWriteNowLocked();
+                scheduleFastWriteLocked();
             }
         }
         if (callbacks != null) {
@@ -837,12 +847,13 @@
         }
     }
 
-    private void scheduleWriteNowLocked() {
-        if (!mWriteScheduled) {
+    private void scheduleFastWriteLocked() {
+        if (!mFastWriteScheduled) {
             mWriteScheduled = true;
+            mFastWriteScheduled = true;
+            mHandler.removeCallbacks(mWriteRunner);
+            mHandler.postDelayed(mWriteRunner, 10*1000);
         }
-        mHandler.removeCallbacks(mWriteRunner);
-        mHandler.post(mWriteRunner);
     }
 
     private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
@@ -1236,12 +1247,11 @@
                             pw.print(" ago");
                         }
                         if (op.duration == -1) {
-                            pw.println(" (running)");
-                        } else {
-                            pw.print("; duration=");
-                                    TimeUtils.formatDuration(op.duration, pw);
-                                    pw.println();
+                            pw.print(" (running)");
+                        } else if (op.duration != 0) {
+                            pw.print("; duration="); TimeUtils.formatDuration(op.duration, pw);
                         }
+                        pw.println();
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7e17043..6823119 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -37,6 +37,7 @@
 import android.app.IActivityContainer;
 import android.app.IActivityContainerCallback;
 import android.app.IAppTask;
+import android.app.ITaskStackListener;
 import android.app.ProfilerInfo;
 import android.app.admin.DevicePolicyManager;
 import android.app.usage.UsageEvents;
@@ -292,7 +293,7 @@
     static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
 
     // Maximum number recent bitmaps to keep in memory.
-    static final int MAX_RECENT_BITMAPS = 5;
+    static final int MAX_RECENT_BITMAPS = 3;
 
     // Amount of time after a call to stopAppSwitches() during which we will
     // prevent further untrusted switches from happening.
@@ -370,6 +371,9 @@
 
     static final int LAST_PREBOOT_DELIVERED_FILE_VERSION = 10000;
 
+    // Delay in notifying task stack change listeners (in millis)
+    static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 1000;
+
     /** All system services */
     SystemServiceManager mSystemServiceManager;
 
@@ -378,6 +382,10 @@
     /** Run all ActivityStacks through this */
     ActivityStackSupervisor mStackSupervisor;
 
+    /** Task stack change listeners. */
+    private RemoteCallbackList<ITaskStackListener> mTaskStackListeners =
+            new RemoteCallbackList<ITaskStackListener>();
+
     public IntentFirewall mIntentFirewall;
 
     // Whether we should show our dialogs (ANR, crash, etc) or just perform their
@@ -1219,6 +1227,7 @@
     static final int START_USER_SWITCH_MSG = 46;
     static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47;
     static final int DISMISS_DIALOG_MSG = 48;
+    static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 49;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1738,6 +1747,22 @@
                 d.dismiss();
                 break;
             }
+            case NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG: {
+                synchronized (ActivityManagerService.this) {
+                    int i = mTaskStackListeners.beginBroadcast();
+                    while (i > 0) {
+                        i--;
+                        try {
+                            // Make a one-way callback to the listener
+                            mTaskStackListeners.getBroadcastItem(i).onTaskStackChanged();
+                        } catch (RemoteException e){
+                            // Handled by the RemoteCallbackList
+                        }
+                    }
+                    mTaskStackListeners.finishBroadcast();
+                }
+                break;
+            }
             }
         }
     };
@@ -2332,6 +2357,16 @@
         }
     }
 
+    /** Sets the task stack listener that gets callbacks when a task stack changes. */
+    @Override
+    public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException {
+        synchronized (ActivityManagerService.this) {
+            if (listener != null) {
+                mTaskStackListeners.register(listener);
+            }
+        }
+    }
+
     @Override
     public void notifyActivityDrawn(IBinder token) {
         if (DEBUG_VISBILITY) Slog.d(TAG, "notifyActivityDrawn: token=" + token);
@@ -3643,12 +3678,12 @@
                 if(DEBUG_TASKS) Slog.i(TAG, "remove RecentTask " + tr
                         + " when finishing user" + userId);
                 mRecentTasks.remove(i);
-                tr.removedFromRecents(mTaskPersister);
+                tr.removedFromRecents();
             }
         }
 
         // Remove tasks from persistent storage.
-        mTaskPersister.wakeup(null, true);
+        notifyTaskPersisterLocked(null, true);
     }
 
     // Sort by taskId
@@ -3660,7 +3695,7 @@
     };
 
     // Extract the affiliates of the chain containing mRecentTasks[start].
-    private int processNextAffiliateChain(int start) {
+    private int processNextAffiliateChainLocked(int start) {
         final TaskRecord startTask = mRecentTasks.get(start);
         final int affiliateId = startTask.mAffiliatedTaskId;
 
@@ -3695,7 +3730,7 @@
         if (first.mNextAffiliate != null) {
             Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate);
             first.setNextAffiliate(null);
-            mTaskPersister.wakeup(first, false);
+            notifyTaskPersisterLocked(first, false);
         }
         // Everything in the middle is doubly linked from next to prev.
         final int tmpSize = mTmpRecents.size();
@@ -3706,13 +3741,13 @@
                 Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate +
                         " setting prev=" + prev);
                 next.setPrevAffiliate(prev);
-                mTaskPersister.wakeup(next, false);
+                notifyTaskPersisterLocked(next, false);
             }
             if (prev.mNextAffiliate != next) {
                 Slog.w(TAG, "Link error 3 prev=" + prev + " next=" + prev.mNextAffiliate +
                         " setting next=" + next);
                 prev.setNextAffiliate(next);
-                mTaskPersister.wakeup(prev, false);
+                notifyTaskPersisterLocked(prev, false);
             }
             prev.inRecents = true;
         }
@@ -3721,7 +3756,7 @@
         if (last.mPrevAffiliate != null) {
             Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate);
             last.setPrevAffiliate(null);
-            mTaskPersister.wakeup(last, false);
+            notifyTaskPersisterLocked(last, false);
         }
 
         // Insert the group back into mRecentTasks at start.
@@ -3762,7 +3797,7 @@
                 if (task.autoRemoveRecents && task.getTopActivity() == null) {
                     // This situation is broken, and we should just get rid of it now.
                     mRecentTasks.remove(i);
-                    task.removedFromRecents(mTaskPersister);
+                    task.removedFromRecents();
                     i--;
                     N--;
                     Slog.w(TAG, "Removing auto-remove without activity: " + task);
@@ -3807,7 +3842,7 @@
                         if (app == dummyApp || (app.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
                             // Doesn't exist any more!  Good-bye.
                             mRecentTasks.remove(i);
-                            task.removedFromRecents(mTaskPersister);
+                            task.removedFromRecents();
                             i--;
                             N--;
                             Slog.w(TAG, "Removing no longer valid recent: " + task);
@@ -3843,7 +3878,7 @@
         }
 
         // Verify the affiliate chain for each task.
-        for (int i = 0; i < N; i = processNextAffiliateChain(i)) {
+        for (int i = 0; i < N; i = processNextAffiliateChainLocked(i)) {
         }
 
         mTmpRecents.clear();
@@ -4009,12 +4044,12 @@
         }
 
         if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: trimming tasks for " + task);
-        trimRecentsForTask(task, true);
+        trimRecentsForTaskLocked(task, true);
 
         N = mRecentTasks.size();
         while (N >= ActivityManager.getMaxRecentTasksStatic()) {
             final TaskRecord tr = mRecentTasks.remove(N - 1);
-            tr.removedFromRecents(mTaskPersister);
+            tr.removedFromRecents();
             N--;
         }
         task.inRecents = true;
@@ -4079,7 +4114,7 @@
      * If needed, remove oldest existing entries in recents that are for the same kind
      * of task as the given one.
      */
-    int trimRecentsForTask(TaskRecord task, boolean doTrim) {
+    int trimRecentsForTaskLocked(TaskRecord task, boolean doTrim) {
         int N = mRecentTasks.size();
         final Intent intent = task.intent;
         final boolean document = intent != null && intent.isDocument();
@@ -4126,7 +4161,7 @@
             tr.disposeThumbnail();
             mRecentTasks.remove(i);
             if (task != tr) {
-                tr.removedFromRecents(mTaskPersister);
+                tr.removedFromRecents();
             }
             i--;
             N--;
@@ -7989,10 +8024,6 @@
         return list;
     }
 
-    TaskRecord getMostRecentTask() {
-        return mRecentTasks.get(0);
-    }
-
     /**
      * Creates a new RecentTaskInfo from a TaskRecord.
      */
@@ -8221,7 +8252,7 @@
                 TaskRecord task = new TaskRecord(this, mStackSupervisor.getNextTaskId(), ainfo,
                         intent, description);
 
-                int trimIdx = trimRecentsForTask(task, false);
+                int trimIdx = trimRecentsForTaskLocked(task, false);
                 if (trimIdx >= 0) {
                     // If this would have caused a trim, then we'll abort because that
                     // means it would be added at the end of the list but then just removed.
@@ -8231,7 +8262,7 @@
                 final int N = mRecentTasks.size();
                 if (N >= (ActivityManager.getMaxRecentTasksStatic()-1)) {
                     final TaskRecord tr = mRecentTasks.remove(N - 1);
-                    tr.removedFromRecents(mTaskPersister);
+                    tr.removedFromRecents();
                 }
 
                 task.inRecents = true;
@@ -8291,7 +8322,7 @@
 
     private void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess) {
         mRecentTasks.remove(tr);
-        tr.removedFromRecents(mTaskPersister);
+        tr.removedFromRecents();
         ComponentName component = tr.getBaseIntent().getComponent();
         if (component == null) {
             Slog.w(TAG, "No component for base intent of task: " + tr);
@@ -9979,6 +10010,7 @@
         }
     }
 
+    /** Pokes the task persister. */
     void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
         if (task != null && task.stack != null && task.stack.isHomeStack()) {
             // Never persist the home stack.
@@ -9987,6 +10019,13 @@
         mTaskPersister.wakeup(task, flush);
     }
 
+    /** Notifies all listeners when the task stack has changed. */
+    void notifyTaskStackChangedLocked() {
+        mHandler.removeMessages(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
+        Message nmsg = mHandler.obtainMessage(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
+        mHandler.sendMessageDelayed(nmsg, NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY);
+    }
+
     @Override
     public boolean shutdown(int timeout) {
         if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
@@ -10010,12 +10049,12 @@
         mBatteryStatsService.shutdown();
         synchronized (this) {
             mProcessStats.shutdownLocked();
+            notifyTaskPersisterLocked(null, true);
         }
-        notifyTaskPersisterLocked(null, true);
 
         return timedout;
     }
-    
+
     public final void activitySlept(IBinder token) {
         if (localLOGV) Slog.v(TAG, "Activity slept: token=" + token);
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index c12cadb..e37d5f3 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -69,7 +69,7 @@
 final class ActivityRecord {
     static final String TAG = ActivityManagerService.TAG;
     static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
-    final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recent";
+    final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
 
     private static final String TAG_ACTIVITY = "activity";
     private static final String ATTR_ID = "id";
@@ -792,7 +792,7 @@
         }
     }
 
-    void updateThumbnail(Bitmap newThumbnail, CharSequence description) {
+    void updateThumbnailLocked(Bitmap newThumbnail, CharSequence description) {
         if (newThumbnail != null) {
             if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
                     "Setting thumbnail of " + this + " to " + newThumbnail);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ea694ada..ad86aea 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -65,7 +65,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Binder;
@@ -838,7 +837,7 @@
         clearLaunchTime(prev);
         final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
         if (mService.mHasRecents && (next == null || next.noDisplay || next.task != prev.task || uiSleeping)) {
-            prev.updateThumbnail(screenshotActivities(prev), null);
+            prev.updateThumbnailLocked(screenshotActivities(prev), null);
         }
         stopFullyDrawnTraceIfNeeded();
 
@@ -950,7 +949,7 @@
             r.icicle = icicle;
             r.haveState = true;
             r.launchCount = 0;
-            r.updateThumbnail(null, description);
+            r.updateThumbnailLocked(null, description);
         }
         if (!r.stopped) {
             if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
@@ -1060,6 +1059,9 @@
             }
             prev.cpuTimeAtResume = 0; // reset it
         }
+
+        // Notfiy when the task stack has changed
+        mService.notifyTaskStackChangedLocked();
     }
 
     /**
@@ -4105,7 +4107,7 @@
                 // Task creator asked to remove this when done, or this task was a voice
                 // interaction, so it should not remain on the recent tasks list.
                 mService.mRecentTasks.remove(task);
-                task.removedFromRecents(mService.mTaskPersister);
+                task.removedFromRecents();
             }
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 38809cb..d9396d8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2871,6 +2871,7 @@
         final TaskRecord task = r.task;
         task.setLastThumbnail(task.stack.screenshotActivities(r));
         mService.addRecentTaskLocked(task);
+        mService.notifyTaskStackChangedLocked();
         mWindowManager.setAppVisibility(r.appToken, false);
     }
 
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index ee93233..d726685 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -383,12 +383,12 @@
         setNextAffiliate(null);
     }
 
-    void removedFromRecents(TaskPersister persister) {
+    void removedFromRecents() {
         disposeThumbnail();
         closeRecentsChain();
         if (inRecents) {
             inRecents = false;
-            persister.wakeup(this, false);
+            mService.notifyTaskPersisterLocked(this, false);
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 225097f..39718ea 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -215,6 +215,8 @@
     // Default to 5s reevaluation delay.
     private static final int DEFAULT_REEVALUATE_DELAY_MS = 5000;
     private static final int MAX_RETRIES = 10;
+    // Between groups of MAX_RETRIES evaluation attempts, pause 10 mins in hopes ISP outage passes.
+    private static final int REEVALUATE_PAUSE_MS = 10*60*1000;
     private final int mReevaluateDelayMs;
     private int mReevaluateToken = 0;
     private static final int INVALID_UID = -1;
@@ -345,6 +347,7 @@
         public void enter() {
             mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
                     NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo));
+            if (!mUserDoesNotWant) sendMessageDelayed(CMD_FORCE_REEVALUATION, REEVALUATE_PAUSE_MS);
         }
 
         @Override
@@ -360,6 +363,15 @@
                     return NOT_HANDLED;
             }
         }
+
+        @Override
+        public void exit() {
+             // NOTE: This removes the delayed message posted by enter() but will inadvertently
+             // remove any other CMD_FORCE_REEVALUATION in the message queue.  At the moment this
+             // is harmless.  If in the future this becomes problematic a different message could
+             // be used.
+             removeMessages(CMD_FORCE_REEVALUATION);
+        }
     }
 
     // Being in the ValidatedState State indicates a Network is:
diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index bd63e00..3271ebf 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -91,7 +91,7 @@
     @Override
     public String toString() {
         return String.format(Locale.US,
-                "[AudioState isMuted: %b, route; %s, supportedRouteMask: %s]",
+                "[AudioState isMuted: %b, route: %s, supportedRouteMask: %s]",
                 isMuted,
                 audioRouteToString(route),
                 audioRouteToString(supportedRouteMask));
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 04274c7..f3b0586 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -838,6 +838,11 @@
         return mConnectionCapabilities;
     }
 
+    /** @hide */
+    @SystemApi @Deprecated public final int getCallCapabilities() {
+        return getConnectionCapabilities();
+    }
+
     /**
      * Sets the value of the {@link #getAddress()} property.
      *
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index bfd0531..e3a0200 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -2985,23 +2985,26 @@
 writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
 {
     status_t err;
+    const char* kClass = "class";
+    const char* kFragment = "fragment";
     const String8 kTransition("transition");
     const String8 kTransitionPrefix("transition-");
 
     // tag:attribute pairs that should be checked in layout files.
     KeyedVector<String8, Vector<NamespaceAttributePair> > kLayoutTagAttrPairs;
-    addTagAttrPair(&kLayoutTagAttrPairs, "view", NULL, "class");
-    addTagAttrPair(&kLayoutTagAttrPairs, "fragment", NULL, "class");
-    addTagAttrPair(&kLayoutTagAttrPairs, "fragment", RESOURCES_ANDROID_NAMESPACE, "name");
+    addTagAttrPair(&kLayoutTagAttrPairs, "view", NULL, kClass);
+    addTagAttrPair(&kLayoutTagAttrPairs, kFragment, NULL, kClass);
+    addTagAttrPair(&kLayoutTagAttrPairs, kFragment, RESOURCES_ANDROID_NAMESPACE, "name");
 
     // tag:attribute pairs that should be checked in xml files.
     KeyedVector<String8, Vector<NamespaceAttributePair> > kXmlTagAttrPairs;
-    addTagAttrPair(&kXmlTagAttrPairs, "PreferenceScreen", RESOURCES_ANDROID_NAMESPACE, "fragment");
-    addTagAttrPair(&kXmlTagAttrPairs, "header", RESOURCES_ANDROID_NAMESPACE, "fragment");
+    addTagAttrPair(&kXmlTagAttrPairs, "PreferenceScreen", RESOURCES_ANDROID_NAMESPACE, kFragment);
+    addTagAttrPair(&kXmlTagAttrPairs, "header", RESOURCES_ANDROID_NAMESPACE, kFragment);
 
     // tag:attribute pairs that should be checked in transition files.
     KeyedVector<String8, Vector<NamespaceAttributePair> > kTransitionTagAttrPairs;
-    addTagAttrPair(&kTransitionTagAttrPairs, kTransition.string(), NULL, "class");
+    addTagAttrPair(&kTransitionTagAttrPairs, kTransition.string(), NULL, kClass);
+    addTagAttrPair(&kTransitionTagAttrPairs, "pathMotion", NULL, kClass);
 
     const Vector<sp<AaptDir> >& dirs = assets->resDirs();
     const size_t K = dirs.size();