Merge "Import translations. DO NOT MERGE" into nyc-mr1-dev
diff --git a/core/java/android/app/ITransientNotification.aidl b/core/java/android/app/ITransientNotification.aidl
index d5b3ed0..35b53a4 100644
--- a/core/java/android/app/ITransientNotification.aidl
+++ b/core/java/android/app/ITransientNotification.aidl
@@ -19,7 +19,7 @@
 
 /** @hide */
 oneway interface ITransientNotification {
-    void show(IBinder windowToken);
+    void show();
     void hide();
 }
 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index b6955a8..4818910 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -233,7 +233,6 @@
         mSession = getWindowSession();
         mLayout.token = getWindowToken();
         mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
-        mLayout.packageName = mContext.getOpPackageName();
         mViewVisibility = getVisibility() == VISIBLE;
 
         if (!mGlobalListenersAdded) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 4a20619..fe24230 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1734,18 +1734,14 @@
         public CharSequence accessibilityTitle;
 
         /**
-         * Sets a timeout in milliseconds before which the window will be hidden
+         * Sets a timeout in milliseconds before which the window will be removed
          * by the window manager. Useful for transient notifications like toasts
          * so we don't have to rely on client cooperation to ensure the window
-         * is hidden. Must be specified at window creation time. Note that apps
-         * are not prepared to handle their windows being removed without their
-         * explicit request and may try to interact with the removed window
-         * resulting in undefined behavior and crashes. Therefore, we do hide
-         * such windows to prevent them from overlaying other apps.
+         * is removed. Must be specified at window creation time.
          *
          * @hide
          */
-        public long hideTimeoutMilliseconds = -1;
+        public long removeTimeoutMilliseconds = -1;
 
         public LayoutParams() {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
@@ -1881,7 +1877,7 @@
             out.writeInt(needsMenuKey);
             out.writeInt(accessibilityIdOfAnchor);
             TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
-            out.writeLong(hideTimeoutMilliseconds);
+            out.writeLong(removeTimeoutMilliseconds);
         }
 
         public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1935,7 +1931,7 @@
             needsMenuKey = in.readInt();
             accessibilityIdOfAnchor = in.readInt();
             accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-            hideTimeoutMilliseconds = in.readLong();
+            removeTimeoutMilliseconds = in.readLong();
         }
 
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -2157,7 +2153,7 @@
             }
 
             // This can't change, it's only set at window creation time.
-            hideTimeoutMilliseconds = o.hideTimeoutMilliseconds;
+            removeTimeoutMilliseconds = o.removeTimeoutMilliseconds;
 
             return changes;
         }
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index eca10cb..7762675 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -25,8 +25,6 @@
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
@@ -328,6 +326,13 @@
     }
 
     private static class TN extends ITransientNotification.Stub {
+        final Runnable mShow = new Runnable() {
+            @Override
+            public void run() {
+                handleShow();
+            }
+        };
+
         final Runnable mHide = new Runnable() {
             @Override
             public void run() {
@@ -338,13 +343,7 @@
         };
 
         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
-        final Handler mHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                IBinder token = (IBinder) msg.obj;
-                handleShow(token);
-            }
-        };
+        final Handler mHandler = new Handler();
 
         int mGravity;
         int mX, mY;
@@ -380,9 +379,9 @@
          * schedule handleShow into the right thread
          */
         @Override
-        public void show(IBinder windowToken) {
+        public void show() {
             if (localLOGV) Log.v(TAG, "SHOW: " + this);
-            mHandler.obtainMessage(0, windowToken).sendToTarget();
+            mHandler.post(mShow);
         }
 
         /**
@@ -394,7 +393,7 @@
             mHandler.post(mHide);
         }
 
-        public void handleShow(IBinder windowToken) {
+        public void handleShow() {
             if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
                     + " mNextView=" + mNextView);
             if (mView != mNextView) {
@@ -423,9 +422,8 @@
                 mParams.verticalMargin = mVerticalMargin;
                 mParams.horizontalMargin = mHorizontalMargin;
                 mParams.packageName = packageName;
-                mParams.hideTimeoutMilliseconds = mDuration ==
+                mParams.removeTimeoutMilliseconds = mDuration ==
                     Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
-                mParams.token = windowToken;
                 if (mView.getParent() != null) {
                     if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                     mWM.removeView(mView);
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index d681246..d7550a4 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -18,6 +18,7 @@
 #include "CreateJavaOutputStreamAdaptor.h"
 #include <Caches.h>
 #include <hwui/Paint.h>
+#include <renderthread/RenderProxy.h>
 
 #include "core_jni_helpers.h"
 
@@ -1361,6 +1362,14 @@
     return reinterpret_cast<jlong>(pixelRef);
 }
 
+static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
+    LocalScopedBitmap bitmapHandle(bitmapPtr);
+    if (!bitmapHandle.valid()) return;
+    SkBitmap bitmap;
+    bitmapHandle->getSkBitmap(&bitmap);
+    android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmap);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static const JNINativeMethod gBitmapMethods[] = {
@@ -1404,6 +1413,7 @@
                                             (void*)Bitmap_copyPixelsFromBuffer },
     {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
     {   "nativeRefPixelRef",        "(J)J", (void*)Bitmap_refPixelRef },
+    {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
 };
 
 int register_android_graphics_Bitmap(JNIEnv* env)
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index 3dcc736..00a7edd 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -479,6 +479,14 @@
   to: /distribute/stories/index.html
 - from: /distribute/stories/tablets.html
   to: /distribute/stories/index.html
+- from: /distribute/stories/glu-dh.html
+  to: /distribute/stories/games/glu-dh.html
+- from: /distribute/stories/apps/tapps.html
+  to: /distribute/stories/games/tapps.html
+- from: /distribute/stories/apps/upbeat-games.html
+  to: /distribute/stories/games/upbeat-games.html
+- from: /distribute/stories/games/two-dots.html
+  to: /distribute/stories/games/dots.html
 - from: /distribute/googleplay/edu/index.html
   to: /distribute/googleplay/edu/about.html
 - from: /distribute/googleplay/edu/contact.html
diff --git a/docs/html/distribute/stories/apps/aftenposten.jd b/docs/html/distribute/stories/apps/aftenposten.jd
index 149e6bb..a813c00 100644
--- a/docs/html/distribute/stories/apps/aftenposten.jd
+++ b/docs/html/distribute/stories/apps/aftenposten.jd
@@ -2,7 +2,7 @@
 page.metaDescription=Aftenposten upgraded their app and improved user retention.
 page.tags="developerstory", "apps", "googleplay"
 page.image=images/cards/distribute/stories/aftenposten.png
-page.timestamp=1468270114
+page.timestamp=1468901834
 
 @jd:body
 
diff --git a/docs/html/distribute/stories/apps/el-mundo.jd b/docs/html/distribute/stories/apps/el-mundo.jd
index 2ee813d..2dbaeea 100644
--- a/docs/html/distribute/stories/apps/el-mundo.jd
+++ b/docs/html/distribute/stories/apps/el-mundo.jd
@@ -2,7 +2,7 @@
 page.metaDescription=El Mundo uses Material Design principles to enhance their app's user experience.
 page.tags="developerstory", "apps", "googleplay"
 page.image=images/cards/distribute/stories/el-mundo.png
-page.timestamp=1468270112
+page.timestamp=1468901833
 
 @jd:body
 
diff --git a/docs/html/distribute/stories/apps/segundamano.jd b/docs/html/distribute/stories/apps/segundamano.jd
index 4cbf817..7ed4d8e 100644
--- a/docs/html/distribute/stories/apps/segundamano.jd
+++ b/docs/html/distribute/stories/apps/segundamano.jd
@@ -2,7 +2,7 @@
 page.metaDescription=Segundamano developed Android app to increase potential for growth.
 page.tags="developerstory", "apps", "googleplay"
 page.image=images/cards/distribute/stories/segundamano.png
-page.timestamp=1468270110
+page.timestamp=1468901832
 
 @jd:body
 
diff --git a/docs/html/distribute/stories/glu-dh.jd b/docs/html/distribute/stories/games/glu-dh.jd
similarity index 100%
rename from docs/html/distribute/stories/glu-dh.jd
rename to docs/html/distribute/stories/games/glu-dh.jd
diff --git a/docs/html/distribute/stories/apps/tapps.jd b/docs/html/distribute/stories/games/tapps.jd
similarity index 98%
rename from docs/html/distribute/stories/apps/tapps.jd
rename to docs/html/distribute/stories/games/tapps.jd
index 1292139..221b9a8 100644
--- a/docs/html/distribute/stories/apps/tapps.jd
+++ b/docs/html/distribute/stories/games/tapps.jd
@@ -1,8 +1,8 @@
 page.title=Tapps Games Increases Installs by More Than 20% with Store Listing Experiments
 page.metaDescription=Tapps Games increased their use of store listing experiments in the Developer Console, with impressive results.
-page.tags="developerstory", "apps", "googleplay"
+page.tags="developerstory", "games", "googleplay"
 page.image=images/cards/distribute/stories/tapps.png
-page.timestamp=1468270108
+page.timestamp=1468901831
 
 @jd:body
 
diff --git a/docs/html/distribute/stories/games/two-dots.jd b/docs/html/distribute/stories/games/two-dots.jd
deleted file mode 100644
index a2299ce..0000000
--- a/docs/html/distribute/stories/games/two-dots.jd
+++ /dev/null
@@ -1,77 +0,0 @@
-page.title=Two Dots increased installs by 7 percent using Store Listing Experiments
-page.metaDescription=Two Dots, the sequel to the popular game Dots, is a free-to-play puzzle game launched by Playdots, Inc. Playdots decided to use Store Listing Experiments to see if adding a call to action in the games’ store listing short descriptions had an impact on installs.
-page.tags="developerstory", "games", "googleplay"
-page.image=images/cards/distribute/stories/two-dots.png
-page.timestamp=1456431511
-
-@jd:body
-
-
-<h3>Background</h3>
-
-<div class="figure" style="width:113px">
-  <img src="{@docRoot}images/distribute/stories/two-dots-icon.png"
-  height="113" />
-</div>
-
-<p>
-  <a class="external-link"
-  href="https://play.google.com/store/apps/details?id=com.weplaydots.twodotsandroid&hl=en">
-  Two Dots</a>, the sequel to the popular game
-  <a class="external-link"
-  href="https://play.google.com/store/apps/details?id=com.nerdyoctopus.gamedots&hl=en">
-  Dots</a>, is a free-to-play puzzle game launched by Playdots, Inc. in May
-  2014. Since launch it has gained over 30 million downloads, seen over five
-  billion games played, and achieved 15 times the revenue of the original Dots
-  game within a year. Dots decided to use
-  <a class="external-link"
-  href="https://support.google.com/googleplay/android-developer/answer/6227309">
-  Store Listing Experiments</a> to see if adding a call to action in the games'
-  store listing short descriptions had an impact on installs.
-
-</p>
-
-<h3>What they did</h3>
-
-<p>
-  Dots used localized store listing experiments in the Google Play Developer
-  Console to test both games’ short descriptions. They compared the games’
-  current descriptions — the control, with no call to action — against variant
-  descriptions, targeting half of their traffic with the variant descriptions.
-</p>
-
-<h3>Results</h3>
-
-<p>
-  The results showed that the addition of a call to action in the short
-  description had a positive impact on installs.
-</p>
-
-
-  <img
-   src="{@docRoot}images/distribute/stories/two-dots-screenshot.png"
-   srcset=
-  "{@docRoot}images/distribute/stories/two-dots-screenshot.png 1x
-  {@docRoot}images/distribute/stories/two-dots-screenshot_2x.png 2x">
-  <p class="img-caption">
-    Beautifully designed achievements badges encourage unlock
-  </p>
-
-
-<p>
-  In Dots, the conversion rate increased by 2 percent with a simple call to
-  action in the variant text. In Two Dots, where a call to action was combined
-  with messaging that the game is the “best puzzle game on Android”, conversion
-  rates increased by 7 percent compared to the control description.
-</p>
-
-<h3>Get started</h3>
-
-<p>
-  Learn how to run
-  <a clas="external-link"
-  href="https://support.google.com/googleplay/android-developer/answer/6227309">
-  Store Listing Experiments</a> and read our best practices for
-  <a href="https://developer.android.com/distribute/users/experiments.html">
-  running successful experiments</a>.
-</p>
diff --git a/docs/html/distribute/stories/apps/upbeat-games.jd b/docs/html/distribute/stories/games/upbeat-games.jd
similarity index 96%
rename from docs/html/distribute/stories/apps/upbeat-games.jd
rename to docs/html/distribute/stories/games/upbeat-games.jd
index 02222d3..16a1d51 100644
--- a/docs/html/distribute/stories/apps/upbeat-games.jd
+++ b/docs/html/distribute/stories/games/upbeat-games.jd
@@ -1,8 +1,8 @@
 page.title=Witch Puzzle Achieves 98% of International Installs on Android
 page.metaDescription=Witch Puzzle localized their app into 12 languages.
-page.tags="developerstory", "apps", "googleplay"
+page.tags="developerstory", "games", "googleplay"
 page.image=images/cards/distribute/stories/witch-puzzle.png
-page.timestamp=1468270106
+page.timestamp=1468901832
 
 @jd:body
 
diff --git a/docs/html/distribute/stories/index.jd b/docs/html/distribute/stories/index.jd
index 8fe1019..1adc5ae 100644
--- a/docs/html/distribute/stories/index.jd
+++ b/docs/html/distribute/stories/index.jd
@@ -19,21 +19,43 @@
 <section class="dac-section dac-small" id="latest-apps"><div class="wrap">
   <h2 class="norule">Latest from apps</h2>
 
+  <h3 class="norule">Videos</h3>
+
   <div class="resource-widget resource-flow-layout col-16"
-      data-query="type:distribute+tag:developerstory+tag:apps, type:youtube+tag:developerstory+tag:apps"
+      data-query="type:youtube+tag:developerstory+tag:apps"
       data-sortOrder="-timestamp"
       data-cardSizes="6x6"
       data-items-per-page="15"
-      data-initial-results="9"></div>
+      data-initial-results="6"></div>
+
+  <h3 class="norule">Articles</h3>
+
+  <div class="resource-widget resource-flow-layout col-16"
+      data-query="type:distribute+tag:developerstory+tag:apps"
+      data-sortOrder="-timestamp"
+      data-cardSizes="6x6"
+      data-items-per-page="15"
+      data-initial-results="6"></div>
 </div></section>
 
 <section class="dac-section dac-small" id="latest-games"><div class="wrap">
   <h2 class="norule">Latest from games</h2>
 
+  <h3 class="norule">Videos</h3>
+
   <div class="resource-widget resource-flow-layout col-16"
-      data-query="type:distribute+tag:developerstory+tag:games,type:youtube+tag:developerstory+tag:games"
+      data-query="type:youtube+tag:developerstory+tag:games"
       data-sortOrder="-timestamp"
       data-cardSizes="6x6"
       data-items-per-page="15"
-      data-initial-results="9"></div>
+      data-initial-results="6"></div>
+
+  <h3 class="norule">Articles</h3>
+
+  <div class="resource-widget resource-flow-layout col-16"
+      data-query="type:distribute+tag:developerstory+tag:games"
+      data-sortOrder="-timestamp"
+      data-cardSizes="6x6"
+      data-items-per-page="15"
+      data-initial-results="6"></div>
 </div></section>
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index 10841d6..9b32244 100755
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -1230,7 +1230,7 @@
     </p>
 
     <p>
-      When declared as required, this feature indicates that the app is
+      By default, your app requires this feature. This feature indicates that the app is
       compatible with a device only if that device emulates a touchscreen
       ("fake touch" interface) or has an actual touchscreen.
     </p>
@@ -1240,19 +1240,12 @@
       that emulates a subset of a touchscreen's capabilities. For example, a
       mouse or remote control could drive an on-screen cursor. If your app
       requires basic point and click interaction (in other words, it won't work
-      with only a d-pad controller), you should declare this feature. Because
+      with only a d-pad controller), you should declare this feature or simply
+      avoid declaring any {@code android.hardware.touchscreen.*} features. Because
       this is the minimum level of touch interaction, you can also use an app
       that declares this feature on devices that offer more complex touch
       interfaces.
     </p>
-
-    <p class="note">
-      <strong>Note:</strong> Apps require the {@code android.hardware.touchscreen}
-      feature by default. If you want your app to be available to devices that
-      provide a fake touch interface, you must also explicitly declare that a
-      touchscreen is not required as follows:
-    </p>
-    <pre>&lt;uses-feature android:name="android.hardware.touchscreen" <strong>android:required="false"</strong> /&gt;</pre>
   </dd>
 
   <dt>
@@ -1327,21 +1320,9 @@
     </p>
 
     <p>
-      By default, your app requires this feature. As such, your app is not
-      available to devices that provide only an emulated touch interface ("fake
-      touch") by default. If you want to make your app available on devices
-      that provide a fake touch interface (or even on devices that provide only
-      a d-pad controller), you must explicitly declare that a touchscreen is
-      not required by declaring {@code android.hardware.touchscreen} with
-      {@code android:required="false"}. You should add this declaration if your
-      app uses—but does not require—a real touchscreen interface.
-    </p>
-
-    <p>
       If your app in fact requires a touch interface (to perform more advanced
-      touch gestures such as fling), then you don't need to declare any touch
-      interface features because they're required by default. However, it's
-      best if you explicitly declare all features that your app uses.
+      touch gestures such as fling), then you must explicitly declare this feature
+      or any advanced touchscreen features.
     </p>
 
     <p>
diff --git a/docs/html/topic/arc/_book.yaml b/docs/html/topic/arc/_book.yaml
new file mode 100644
index 0000000..ad83ba9
--- /dev/null
+++ b/docs/html/topic/arc/_book.yaml
@@ -0,0 +1,9 @@
+toc:
+- title: Optimize Apps for Chromebooks
+  path: /topic/arc/index.html
+- title: Loading Apps on Chromebooks
+  path: /topic/arc/sideload.html
+- title: Chrome OS Device Support for Apps
+  path: /topic/arc/device-support.html
+- title: App Manifest Compatibility for Chromebooks
+  path: /topic/arc/manifest.html
\ No newline at end of file
diff --git a/docs/html/training/_book.yaml b/docs/html/training/_book.yaml
index 0523ec9e..891574f 100644
--- a/docs/html/training/_book.yaml
+++ b/docs/html/training/_book.yaml
@@ -1384,6 +1384,11 @@
     path_attributes:
     - name: description
       value: How to use the SafetyNet service to analyze a device where your app is running and get information about its compatibility with your app.
+  - title: Checking URLs with the Safe Browsing API
+    path: /training/safebrowsing/index.html
+    path_attributes:
+    - name: description
+      value: How to use the SafetyNet service to determine if a URL is designated as a known threat.
   - title: Verifying Hardware-backed Key Pairs with Key Attestation
     path: /training/articles/security-key-attestation.html
     path_attributes:
diff --git a/docs/html/training/safebrowsing/index.jd b/docs/html/training/safebrowsing/index.jd
new file mode 100644
index 0000000..c6c72bf
--- /dev/null
+++ b/docs/html/training/safebrowsing/index.jd
@@ -0,0 +1,315 @@
+page.title=Checking URLs with the Safe Browsing API
+
+@jd:body
+
+
+<div id="tb-wrapper">
+  <div id="tb">
+    <h2>
+      In this document
+    </h2>
+
+    <ol>
+      <li>
+        <a href="#tos">Terms of Service</a>
+      </li>
+
+      <li>
+        <a href="#api-key">Requesting and Registering an Android API Key</a>
+        <ol>
+          <li>
+            <a href="#manifest">Adding the Android API to your
+            AndroidManifest.xml</a>
+          </li>
+        </ol>
+      </li>
+
+      <li>
+        <a href="#connect-google-play">Connect to Google Play Services</a>
+      </li>
+
+      <li>
+        <a href="#url-check">Requesting a URL Check</a>
+        <ol>
+          <li>
+            <a href="#threat-types">Specifying threat types of interest</a>
+          </li>
+
+          <li>
+            <a href="#url-check-request">Send the URL check request</a>
+          </li>
+
+          <li>
+            <a href="#url-check-response">Read the URL check response</a>
+          </li>
+        </ol>
+      </li>
+
+      <li>
+        <a href="#warning-lang">Suggested Warning Language</a>
+      </li>
+    </ol>
+  </div>
+</div>
+
+<p>
+  SafetyNet provides services for determining whether a URL has been marked as
+  a known threat by Google.
+</p>
+
+<p>
+  The service provides an API your app can use to determine whether a
+  particular URL has been classified by Google as a known threat. Internally,
+  SafetyNet implements a client for the Safe Browsing Network Protocol v4
+  developed by Google. Both the client code and the v4 network protocol were
+  designed to preserve users' privacy, as well as keep battery and bandwidth
+  consumption to a minimum. This API allows you to take full advantage of
+  Google's Safe Browsing service on Android in the most resource-optimized way,
+  and without having to implement its network protocol.
+</p>
+
+<p>
+  This document shows you how to use SafetyNet for checking a URL for threat
+  types of interest.
+</p>
+
+<h2 id="tos">
+  Terms of Service
+</h2>
+
+<p>
+  By using the Safe Browsing API, you consent to be bound by the <a href=
+  "https://developers.google.com/safe-browsing/terms">Terms of Service</a>.
+  Please read and understand all applicable terms and policies before accessing
+  the Safe Browsing API.
+</p>
+
+<h2 id="api-key">
+  Requesting and Registering an Android API Key
+</h2>
+
+<p>
+  To create an API key, complete the following steps:
+</p>
+
+<ol>
+  <li>Go to the <a href="https://console.developers.google.com/project"
+    class="external-link">Google Developers Console</a>.
+  </li>
+
+  <li>On the upper toolbar, choose <strong>Select a project &gt;
+  <em>your-project-name</em></strong>.
+  </li>
+
+  <li>In the search box, enter <em>Safe Browsing APIs</em>; when the Safe
+  Browsing API name appears in the table, select it.
+  </li>
+
+  <li>After the page redisplays, select <strong>Enable</strong> then select
+  <strong>Go to Credentials</strong>.
+  </li>
+
+  <li>When the <em>Add credentials to your project</em> window appears, choose
+  your parameters then select <strong>What credentials do I need?</strong>.
+  </li>
+
+  <li>Enter a name for your API key then select <strong>Create API
+  key</strong>.
+  </li>
+
+  <li>
+    <p>
+      Your new API key appears; copy and paste this key for future use.
+    </p>
+
+    <p class="note">
+      <strong>Note:</strong> Your API key allows you to perform a URL check
+      10,000 times each day. The key, in this instance, should just be a
+      hexadecimal string, not part of a URL.
+    </p>
+  </li>
+
+  <li>Select <strong>Done</strong> to complete the process.
+  </li>
+</ol>
+
+<p>
+  If you need more help, check out the <a href=
+  "https://developers.google.com/console/help/new/">Google Developers Console
+  Help Center</a>.
+</p>
+
+<h3 id="manifest">
+  Adding the Android API key to your AndroidManifest.xml
+</h3>
+
+<p>
+  Once your key has been whitelisted, you need to add the key to the
+  <code>AndroidManifest.xml</code> file for your app:
+</p>
+
+<pre>
+&lt;application&gt;
+
+    ...
+
+   &lt;!-- SafetyNet API metadata --&gt;
+   &lt;meta-data android:name="com.google.android.safetynet.API_KEY"
+   android:value="<var>your-API-key</var>" /&gt;
+
+    ...
+
+&lt;/application&gt;
+</pre>
+<h2 id="connect-google-play">
+  Connect to Google Play Services
+</h2>
+
+<p>
+  The SafetyNet API is part of Google Play services. To connect to the API, you
+  need to create an instance of the Google Play services API client. For
+  details about using the client in your app, see <a href=
+  "https://developers.google.com/android/guides/api-client#Starting">Accessing
+  Google APIs</a>. Once you have established a connection to Google Play
+  services, you can use the Google API client classes to connect to the
+  SafetyNet API.
+</p>
+
+<p>
+  To connect to the API, in your activity's <code><a href=
+  "{@docRoot}reference/android/app/Activity.html#onCreate(android.os.Bundle)">onCreate()</a></code>
+  method, create an instance of Google API Client using <code><a href=
+  "https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.Builder">
+  GoogleApiClient.Builder</a></code>. Use the builder to add the SafetyNet API,
+  as shown in the following code example:
+</p>
+
+<pre>
+protected synchronized void buildGoogleApiClient() {
+    mGoogleApiClient = new GoogleApiClient.Builder(this)
+            .addApi(SafetyNet.API)
+            .addConnectionCallbacks(myMainActivity.this)
+            .build();
+}
+</pre>
+<p class="note">
+  <strong>Note:</strong> You can only call these methods after your app has
+  established a connection to Google Play services by receiving the <code>
+  <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks#public-methods">
+  onConnected()</a></code> callback. For details about listening for a completed
+  client connection, see <a href=
+  "https://developers.google.com/android/guides/api-client#Starting">Accessing
+  Google APIs</a>.
+</p>
+
+<h2 id="url-check">
+  Requesting a URL Check
+</h2>
+
+<p>
+  A URL check allows your app to determine if a URL has been marked as a threat
+  of interest. Some threat types may not be of interest to your particular
+  app, and the API allows you to choose which threat types are important for
+  your needs. You can specify multiple threat types of interest.
+</p>
+
+<h3 id="threat-types">
+  Specifying threat types of interest
+</h3>
+
+<p>
+  The constants in the {@code SafeBrowsingThreat} class contain the
+  currently-supported threat types:
+</p>
+
+<pre>
+package com.google.android.gms.safetynet;
+
+public class SafeBrowsingThreat {
+
+  /**
+   * This threat type identifies URLs of pages that are flagged as containing potentially
+   * harmful applications.
+   */
+  public static final int TYPE_POTENTIALLY_HARMFUL_APPLICATION = 4;
+
+  /**
+   * This threat type identifies URLs of pages that are flagged as containing social
+   * engineering threats.
+   */
+  public static final int TYPE_SOCIAL_ENGINEERING = 5;
+}
+</pre>
+<p>
+  When using the API, you must use constants that are not marked as deprecated.
+  You add threat type constants as arguments to the API. You may add as many
+  threat type constants as is required for your app.
+</p>
+
+<h3 id="url-check-request">
+  Send the URL check request
+</h3>
+
+<p>
+  The API is agnostic to the scheme used, so you can pass the URL with or
+  without a scheme. For example, either
+</p>
+
+<pre>
+String url = "https://www.google.com";
+</pre>
+<p>
+  or
+</p>
+
+<pre>
+String url = "www.google.com";
+</pre>
+<p>
+  is valid.
+</p>
+
+<pre>
+SafetyNet.SafetyNetApi.lookupUri(mGoogleApiClient, url,
+       SafeBrowsingThreat.TYPE_POTENTIALLY_HARMFUL_APPLICATION,
+       SafeBrowsingThreat.TYPE_SOCIAL_ENGINEERING)
+               .setResultCallback(
+                       new ResultCallback&lt;SafetyNetApi.SafeBrowsingResult&gt;() {
+
+    &#64;Override
+    public void onResult(SafetyNetApi.SafeBrowsingResult result) {
+        Status status = result.getStatus();
+        if ((status != null) &amp;&amp; status.isSuccess()) {
+            // Indicates communication with the service was successful.
+            // Identify any detected threats.
+            if (result.getDetectedThreats().isEmpty()) {
+
+            }
+        } else {
+            // An error occurred. Let the user proceed without warning.
+        }
+    }
+});
+</pre>
+<h3 id="url-check-response">
+  Read the URL check response
+</h3>
+
+<p>
+  The result is provided as a list of {@code SafeBrowsingThreat} objects by
+  calling the {@code SafetyNetApi.SafeBrowsingResult.getDetectedThreats()}
+  method of the returned {@code SafetyNetApi.SafeBrowsingResult} object. If the
+  list is empty, no threats were detected; otherwise, calling {@code
+  SafeBrowsingThreat.getThreatType()} on each element in the list enumerates
+  the threats that were detected.
+</p>
+
+<h2 id="warning-lang">
+  Suggested Warning Language
+</h2>
+
+<p>
+  Please see the Safe Browsing API Developer's Guide for <a href=
+  "https://developers.google.com/safe-browsing/v4/usage-limits#suggested--warning-language">
+  suggested warning language</a>.
+</p>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 1fdc1f5..49721cf 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1667,10 +1667,10 @@
      * and therefore is harmless.
      */
     public void prepareToDraw() {
-        // TODO: Consider having this start an async upload?
-        // With inPurgeable no-op'd there's currently no use for this
-        // method, but it could have interesting future uses.
         checkRecycled("Can't prepareToDraw on a recycled bitmap!");
+        // Kick off an update/upload of the bitmap outside of the normal
+        // draw path.
+        nativePrepareToDraw(mNativePtr);
     }
 
     /**
@@ -1741,4 +1741,5 @@
     private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
     private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
     private static native long nativeRefPixelRef(long nativeBitmap);
+    private static native void nativePrepareToDraw(long nativeBitmap);
 }
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index ade8600..523924a 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -167,6 +167,10 @@
     return texture;
 }
 
+bool TextureCache::prefetch(const SkBitmap* bitmap) {
+    return getCachedTexture(bitmap, AtlasUsageType::Use);
+}
+
 Texture* TextureCache::get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType) {
     Texture* texture = getCachedTexture(bitmap, atlasUsageType);
 
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index a4317ce..0a61b6b 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -78,6 +78,13 @@
     bool prefetchAndMarkInUse(void* ownerToken, const SkBitmap* bitmap);
 
     /**
+     * Attempts to precache the SkBitmap. Returns true if a Texture was successfully
+     * acquired for the bitmap, false otherwise. Does not mark the Texture
+     * as in use and won't update currently in-use Textures.
+     */
+    bool prefetch(const SkBitmap* bitmap);
+
+    /**
      * Returns the texture associated with the specified bitmap from either within the cache, or
      * the AssetAtlas. If the texture cannot be found in the cache, a new texture is generated.
      */
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index d68f0e3..c6b258b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -562,11 +562,16 @@
         swap.damage = screenDirty;
         swap.swapCompletedTime = systemTime(CLOCK_MONOTONIC);
         swap.vsyncTime = mRenderThread.timeLord().latestVsync();
-        int durationUs;
-        mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs);
-        swap.dequeueDuration = us2ns(durationUs);
-        mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs);
-        swap.queueDuration = us2ns(durationUs);
+        if (mNativeSurface.get()) {
+            int durationUs;
+            mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs);
+            swap.dequeueDuration = us2ns(durationUs);
+            mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs);
+            swap.queueDuration = us2ns(durationUs);
+        } else {
+            swap.dequeueDuration = 0;
+            swap.queueDuration = 0;
+        }
         mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration)
                 = swap.dequeueDuration;
         mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration)
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 06a24b2..fb1c896 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -22,9 +22,11 @@
 #include "Readback.h"
 #include "Rect.h"
 #include "renderthread/CanvasContext.h"
+#include "renderthread/EglManager.h"
 #include "renderthread/RenderTask.h"
 #include "renderthread/RenderThread.h"
 #include "utils/Macros.h"
+#include "utils/TimeUtils.h"
 
 namespace android {
 namespace uirenderer {
@@ -44,6 +46,8 @@
     typedef struct { \
         a1; a2; a3; a4; a5; a6; a7; a8; \
     } ARGS(name); \
+    static_assert(std::is_trivially_destructible<ARGS(name)>::value, \
+            "Error, ARGS must be trivially destructible!"); \
     static void* Bridge_ ## name(ARGS(name)* args)
 
 #define SETUP_TASK(method) \
@@ -636,6 +640,41 @@
             reinterpret_cast<intptr_t>( staticPostAndWait(task) ));
 }
 
+CREATE_BRIDGE2(prepareToDraw, RenderThread* thread, SkBitmap* bitmap) {
+    if (Caches::hasInstance() && args->thread->eglManager().hasEglContext()) {
+        ATRACE_NAME("Bitmap#prepareToDraw task");
+        Caches::getInstance().textureCache.prefetch(args->bitmap);
+    }
+    delete args->bitmap;
+    args->bitmap = nullptr;
+    return nullptr;
+}
+
+void RenderProxy::prepareToDraw(const SkBitmap& bitmap) {
+    // If we haven't spun up a hardware accelerated window yet, there's no
+    // point in precaching these bitmaps as it can't impact jank.
+    // We also don't know if we even will spin up a hardware-accelerated
+    // window or not.
+    if (!RenderThread::hasInstance()) return;
+    RenderThread* renderThread = &RenderThread::getInstance();
+    SETUP_TASK(prepareToDraw);
+    args->thread = renderThread;
+    args->bitmap = new SkBitmap(bitmap);
+    nsecs_t lastVsync = renderThread->timeLord().latestVsync();
+    nsecs_t estimatedNextVsync = lastVsync + renderThread->timeLord().frameIntervalNanos();
+    nsecs_t timeToNextVsync = estimatedNextVsync - systemTime(CLOCK_MONOTONIC);
+    // We expect the UI thread to take 4ms and for RT to be active from VSYNC+4ms to
+    // VSYNC+12ms or so, so aim for the gap during which RT is expected to
+    // be idle
+    // TODO: Make this concept a first-class supported thing? RT could use
+    // knowledge of pending draws to better schedule this task
+    if (timeToNextVsync > -6_ms && timeToNextVsync < 1_ms) {
+        renderThread->queueAt(task, estimatedNextVsync + 8_ms);
+    } else {
+        renderThread->queue(task);
+    }
+}
+
 void RenderProxy::post(RenderTask* task) {
     mRenderThread.queue(task);
 }
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index e31062c8..bb111bd 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -129,6 +129,7 @@
     ANDROID_API long getDroppedFrameReportCount();
 
     ANDROID_API static int copySurfaceInto(sp<Surface>& surface, SkBitmap* bitmap);
+    ANDROID_API static void prepareToDraw(const SkBitmap& bitmap);
 
 private:
     RenderThread& mRenderThread;
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 121a896..e1b2c50 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -110,9 +110,9 @@
     <string name="menu_rename" msgid="7678802479104285353">"名前を変更"</string>
     <string name="rename_error" msgid="4203041674883412606">"ドキュメントの名前を変更できませんでした"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"一部のファイルが変換されました"</string>
-    <string name="open_external_dialog_request" msgid="5789329484285817629">"「<xliff:g id="STORAGE"><i>^3</i></xliff:g>」の「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」ディレクトリに「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」へのアクセスを許可しますか?"</string>
-    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」アプリに「<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>」ディレクトリへのアクセスを許可しますか?"</string>
-    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g>の写真や動画などのデータへのアクセスを「<xliff:g id="APPNAME"><b>^1</b></xliff:g>」に許可しますか?"</string>
+    <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="STORAGE"><i>^3</i></xliff:g> の <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ディレクトリに <xliff:g id="APPNAME"><b>^1</b></xliff:g> へのアクセスを許可しますか?"</string>
+    <string name="open_external_dialog_request_primary_volume" msgid="6635562535713428688">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> アプリに <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> ディレクトリへのアクセスを許可しますか?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="STORAGE"><i>^2</i></xliff:g>の写真や動画などのデータへのアクセスを <xliff:g id="APPNAME"><b>^1</b></xliff:g> に許可しますか?"</string>
     <string name="never_ask_again" msgid="4295278542972859268">"今後表示しない"</string>
     <string name="allow" msgid="7225948811296386551">"許可"</string>
     <string name="deny" msgid="2081879885755434506">"拒否"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index fb7180a..99850a5 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -111,7 +111,7 @@
     <string name="tts_play_example_summary" msgid="8029071615047894486">"Reprodueix una breu demostració de síntesi de veu"</string>
     <string name="tts_install_data_title" msgid="4264378440508149986">"Instal·la dades de veu"</string>
     <string name="tts_install_data_summary" msgid="5742135732511822589">"Instal·la les dades de veu necessàries per a la síntesi de veu"</string>
-    <string name="tts_engine_security_warning" msgid="8786238102020223650">"Pot ser que aquest motor de síntesi de la parla pugui recopilar tot el text que es dirà en veu alta, incloses les dades personals, com ara les contrasenyes i els números de les targetes de crèdit. Ve del motor <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Voleu activar l\'ús d\'aquest motor de síntesi de la parla?"</string>
+    <string name="tts_engine_security_warning" msgid="8786238102020223650">"Pot ser que aquest motor de síntesi de la parla pugui recopilar tot el text que es dirà en veu alta, incloses les dades personals, com ara les contrasenyes i els números de les targetes de crèdit. Ve del motor <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Vols activar l\'ús d\'aquest motor de síntesi de la parla?"</string>
     <string name="tts_engine_network_required" msgid="1190837151485314743">"Aquest idioma requereix una connexió de xarxa activa per a la sortida de síntesi de veu."</string>
     <string name="tts_default_sample_string" msgid="4040835213373086322">"Això és un exemple de síntesi de veu"</string>
     <string name="tts_status_title" msgid="7268566550242584413">"Estat de l\'idioma predeterminat"</string>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index 73cd181..9734b2e 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -21,7 +21,7 @@
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Raport o błędzie <xliff:g id="ID">#%d</xliff:g> został zapisany"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Dodaję szczegóły do raportu o błędzie"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Czekaj..."</string>
-    <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Raport o błędzie będzie się pojawiał na telefonie przez chwilę"</string>
+    <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Raport o błędzie będzie pojawiał się na telefonie przez chwilę"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Kliknij, by udostępnić raport o błędzie"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Kliknij, by udostępnić raport o błędzie bez zrzutu ekranu, lub poczekaj, aż zostanie on wygenerowany"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Kliknij, by udostępnić raport o błędzie bez zrzutu ekranu, lub poczekaj, aż zostanie on wygenerowany"</string>
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
index 67e6a01..e207cb3 100644
--- a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
@@ -98,11 +98,11 @@
             <path
                 android:name="path_2"
                 android:pathData="M 1.35900878906,6.76104736328 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-2.69995117188 0.0,-2.69995117188 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,2.69995117188 0.0,2.69995117188 Z"
-                android:fillColor="#FFF2501D" />
+                android:fillColor="@*android:color/system_error" />
             <path
                 android:name="path_1"
                 android:pathData="M 1.35363769531,1.36633300781 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-8.09997558594 0.0,-8.09997558594 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,8.09997558594 0.0,8.09997558594 Z"
-                android:fillColor="#FFF2501D" />
+                android:fillColor="@*android:color/system_error" />
         </group>
     </group>
     <group
@@ -117,7 +117,7 @@
             <path
                 android:name="path_3"
                 android:pathData="M 0.0101470947266,10.8087768555 c -5.96701049805,0.0 -10.8000183105,-4.8330078125 -10.8000183105,-10.8000488281 c 0.0,-5.96691894531 4.8330078125,-10.7999267578 10.8000183105,-10.7999267578 c 5.96697998047,0.0 10.799987793,4.8330078125 10.799987793,10.7999267578 c 0.0,5.96704101562 -4.8330078125,10.8000488281 -10.799987793,10.8000488281 Z"
-                android:strokeColor="#FFF2501D"
+                android:strokeColor="@*android:color/system_error"
                 android:strokeWidth="2"
                 android:trimPathStart="0"
                 android:trimPathEnd="1" />
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
index bbadec1..2b4babc 100644
--- a/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
@@ -96,7 +96,7 @@
                 <path
                     android:name="ridge_5_path_0"
                     android:pathData="M -25.3591003418,-24.4138946533 c -0.569000244141,0.106399536133 -1.12660217285,0.140594482422 -1.45460510254,0.140594482422 c -1.29689025879,0.0 -2.53239440918,-0.343307495117 -3.62019348145,-1.12400817871 c -1.67700195312,-1.20349121094 -2.76950073242,-3.17008972168 -2.76950073242,-5.39189147949"
-                    android:strokeColor="#FFF2501D"
+                    android:strokeColor="@*android:color/system_error"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -106,7 +106,7 @@
                 <path
                     android:name="ridge_7_path_0"
                     android:pathData="M -36.1409912109,-21.7843475342 c -1.00540161133,-1.19300842285 -1.57499694824,-1.9181060791 -2.36520385742,-3.50170898438 c -0.827560424805,-1.65869140625 -1.31352233887,-3.49159240723 -1.31352233887,-5.48489379883 c 0.0,-3.66279602051 2.96932983398,-6.63220214844 6.63221740723,-6.63220214844 c 3.6628112793,0.0 6.63220214844,2.96940612793 6.63220214844,6.63220214844"
-                    android:strokeColor="#FFF2501D"
+                    android:strokeColor="@*android:color/system_error"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -116,7 +116,7 @@
                 <path
                     android:name="ridge_6_path_0"
                     android:pathData="M -42.1907958984,-25.6756896973 c -0.758117675781,-2.14370727539 -0.896545410156,-3.86891174316 -0.896545410156,-5.12921142578 c 0.0,-1.46069335938 0.249176025391,-2.84799194336 0.814682006836,-4.09748840332 c 1.56153869629,-3.45030212402 5.03434753418,-5.85076904297 9.0679473877,-5.85076904297 c 5.49430847168,0.0 9.94830322266,4.4539642334 9.94830322266,9.94825744629 c 0.0,1.83151245117 -1.48460388184,3.31610107422 -3.31610107422,3.31610107422 c -1.83149719238,0.0 -3.31610107422,-1.48469543457 -3.31610107422,-3.31610107422 c 0.0,-1.83139038086 -1.48458862305,-3.31610107422 -3.31610107422,-3.31610107422 c -1.83149719238,0.0 -3.31610107422,1.48471069336 -3.31610107422,3.31610107422 c 0.0,2.57020568848 0.989517211914,4.88710021973 2.60510253906,6.5865020752 c 1.22210693359,1.28550720215 2.43139648438,2.09950256348 4.47590637207,2.69030761719"
-                    android:strokeColor="#FFF2501D"
+                    android:strokeColor="@*android:color/system_error"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -126,7 +126,7 @@
                 <path
                     android:name="ridge_2_path_0"
                     android:pathData="M -44.0646514893,-38.1672973633 c 1.19026184082,-1.77430725098 2.67503356934,-3.24531555176 4.55902099609,-4.27278137207 c 1.88395690918,-1.0274810791 4.04466247559,-1.61137390137 6.34175109863,-1.61137390137 c 2.28761291504,0.0 4.43991088867,0.579071044922 6.31831359863,1.59861755371 c 1.8784942627,1.01954650879 3.36059570312,2.4796295166 4.55279541016,4.24153137207"
-                    android:strokeColor="#FFF2501D"
+                    android:strokeColor="@*android:color/system_error"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathStart="1" />
@@ -138,7 +138,7 @@
                 <path
                     android:name="ridge_1_path_0"
                     android:pathData="M 71.7812347412,97.0507202148 c -2.27149963379,-1.31344604492 -4.71360778809,-2.07006835938 -7.56221008301,-2.07006835938 c -2.84869384766,0.0 -5.23320007324,0.779556274414 -7.34411621094,2.07006835938"
-                    android:strokeColor="#FFF2501D"
+                    android:strokeColor="@*android:color/system_error"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -157,11 +157,11 @@
             <path
                 android:name="path_2"
                 android:pathData="M -1.3705291748,4.06730651855 c 0.0,0.0 0.036376953125,-0.0102386474609 0.036376953125,-0.0102386474609 c 0.0,0.0 -0.00682067871094,0.0040283203125 -0.00682067871093,0.0040283203125 c 0.0,0.0 -0.0161437988281,0.00479125976562 -0.0161437988281,0.00479125976563 c 0.0,0.0 -0.0134124755859,0.00141906738281 -0.0134124755859,0.00141906738281 Z"
-                android:fillColor="#FFF2501D" />
+                android:fillColor="@*android:color/system_error" />
             <path
                 android:name="path_1"
                 android:pathData="M -1.3737487793,-6.77532958984 c 0.0,0.0 0.00604248046875,0.0166625976562 0.00604248046876,0.0166625976562 c 0.0,0.0 0.0213623046875,0.0250244140625 0.0213623046875,0.0250244140625 c 0.0,0.0 -0.00604248046875,-0.0166625976562 -0.00604248046876,-0.0166625976562 c 0.0,0.0 -0.0213623046875,-0.0250244140625 -0.0213623046875,-0.0250244140625 Z"
-                android:fillColor="#FFF2501D" />
+                android:fillColor="@*android:color/system_error" />
         </group>
     </group>
     <group
@@ -176,7 +176,7 @@
             <path
                 android:name="path_3"
                 android:pathData="M 0.0101470947266,10.8087768555 c -5.96701049805,0.0 -10.8000183105,-4.8330078125 -10.8000183105,-10.8000488281 c 0.0,-5.96691894531 4.8330078125,-10.7999267578 10.8000183105,-10.7999267578 c 5.96697998047,0.0 10.799987793,4.8330078125 10.799987793,10.7999267578 c 0.0,5.96704101562 -4.8330078125,10.8000488281 -10.799987793,10.8000488281 Z"
-                android:strokeColor="#FFF2501D"
+                android:strokeColor="@*android:color/system_error"
                 android:strokeWidth="2"
                 android:trimPathStart="1" />
         </group>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f48039e..c2897cd 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -250,7 +250,7 @@
     <integer name="doze_pulse_duration_in">900</integer>
 
     <!-- Doze: pulse parameter - how long does it take to fade in after a pickup? -->
-    <integer name="doze_pulse_duration_in_pickup">300</integer>
+    <integer name="doze_pulse_duration_in_pickup">130</integer>
 
     <!-- Doze: pulse parameter - once faded in, how long does it stay visible? -->
     <integer name="doze_pulse_duration_visible">3000</integer>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 2d1f753..9415b27 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.app.ActivityManager;
 import android.content.Intent;
 import android.provider.Settings;
 import android.widget.Switch;
@@ -29,11 +30,12 @@
 public class NightDisplayTile extends QSTile<QSTile.BooleanState>
         implements NightDisplayController.Callback {
 
-    private final NightDisplayController mController;
+    private NightDisplayController mController;
+    private boolean mIsListening;
 
     public NightDisplayTile(Host host) {
         super(host);
-        mController = new NightDisplayController(mContext);
+        mController = new NightDisplayController(mContext, ActivityManager.getCurrentUser());
     }
 
     @Override
@@ -54,6 +56,22 @@
     }
 
     @Override
+    protected void handleUserSwitch(int newUserId) {
+        // Stop listening to the old controller.
+        if (mIsListening) {
+            mController.setListener(null);
+        }
+
+        // Make a new controller for the new user.
+        mController = new NightDisplayController(mContext, newUserId);
+        if (mIsListening) {
+            mController.setListener(this);
+        }
+
+        super.handleUserSwitch(newUserId);
+    }
+
+    @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         final boolean isActivated = mController.isActivated();
         state.value = isActivated;
@@ -79,6 +97,7 @@
 
     @Override
     protected void setListening(boolean listening) {
+        mIsListening = listening;
         if (listening) {
             mController.setListener(this);
             refreshState();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index ca59831..ba31e3e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -200,6 +200,10 @@
 
                             if (cachedThumbnailData.thumbnail == null) {
                                 cachedThumbnailData.thumbnail = mDefaultThumbnail;
+                            } else {
+                                // Kick off an early upload of the bitmap to GL so
+                                // that this won't jank the first frame it's drawn in.
+                                cachedThumbnailData.thumbnail.prepareToDraw();
                             }
 
                             // When svelte, we trim the memory to just the visible thumbnails when
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 3193759..c46adf1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -164,6 +164,7 @@
     /** Sets the thumbnail to a given bitmap. */
     void setThumbnail(Bitmap bm, ActivityManager.TaskThumbnailInfo thumbnailInfo) {
         if (bm != null) {
+            bm.prepareToDraw();
             mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
             mDrawPaint.setShader(mBitmapShader);
             mThumbnailRect.set(0, 0, bm.getWidth(), bm.getHeight());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 405ccd6..10facea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -334,6 +334,9 @@
                     || ((CustomTile) tile).getUser() == currentUser)) {
                 if (DEBUG) Log.d(TAG, "Adding " + tile);
                 tile.removeCallbacks();
+                if (!(tile instanceof CustomTile) && mCurrentUser != currentUser) {
+                    tile.userSwitch(currentUser);
+                }
                 newTiles.put(tileSpec, tile);
             } else {
                 if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 5a66140..5624260 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3559,19 +3559,22 @@
         final ActivityState prevState = r.state;
         if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
         r.state = ActivityState.FINISHING;
+        final boolean finishingActivityInNonFocusedStack
+                = r.task.stack != mStackSupervisor.getFocusedStack()
+                && prevState == ActivityState.PAUSED && mode == FINISH_AFTER_VISIBLE;
 
         if (mode == FINISH_IMMEDIATELY
                 || (prevState == ActivityState.PAUSED
-                    && (mode == FINISH_AFTER_PAUSE || mode == FINISH_AFTER_VISIBLE
-                        || mStackId == PINNED_STACK_ID))
+                    && (mode == FINISH_AFTER_PAUSE || mStackId == PINNED_STACK_ID))
+                || finishingActivityInNonFocusedStack
                 || prevState == ActivityState.STOPPED
                 || prevState == ActivityState.INITIALIZING) {
             r.makeFinishingLocked();
             boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
 
-            if (prevState == ActivityState.PAUSED && mode == FINISH_AFTER_VISIBLE) {
-                // Finishing activity that was in paused state - this can happen if it was in
-                // not currently focused stack. Need to make something visible in its place.
+            if (finishingActivityInNonFocusedStack) {
+                // Finishing activity that was in paused state and it was in not currently focused
+                // stack, need to make something visible in its place.
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
             }
             if (activityRemoved) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index a58d243..b47e079 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -176,9 +176,21 @@
 
     private void updateRaParams(RaParams params) {
         if (mRaDaemon != null) {
+            HashSet<IpPrefix> deprecated = null;
+
+            if (mLastRaParams != null) {
+                deprecated = new HashSet<>();
+
+                for (IpPrefix ipp : mLastRaParams.prefixes) {
+                    if (params == null || !params.prefixes.contains(ipp)) {
+                        deprecated.add(ipp);
+                    }
+                }
+            }
+
             // Currently, we send spurious RAs (5) whenever there's any update.
             // TODO: Compare params with mLastParams to avoid spurious updates.
-            mRaDaemon.buildNewRa(params);
+            mRaDaemon.buildNewRa(params, deprecated);
         }
 
         mLastRaParams = params;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index de1d7a7..8b5942c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -58,6 +58,7 @@
 import android.app.NotificationManager;
 import android.app.NotificationManager.Policy;
 import android.app.PendingIntent;
+import android.app.RemoteInput;
 import android.app.StatusBarManager;
 import android.app.backup.BackupManager;
 import android.app.usage.UsageEvents;
@@ -92,6 +93,7 @@
 import android.os.IInterface;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -120,8 +122,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
-import android.view.WindowManager;
-import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.Toast;
@@ -138,7 +138,6 @@
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
-import com.android.server.policy.PhoneWindowManager;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.vr.VrManagerInternal;
 import com.android.server.notification.ManagedServices.UserProfiles;
@@ -194,7 +193,7 @@
     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
     private static final int MESSAGE_RANKING_SORT = 1001;
 
-    static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
+    static final int LONG_DELAY = 3500; // 3.5 seconds
     static final int SHORT_DELAY = 2000; // 2 seconds
 
     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
@@ -233,7 +232,6 @@
     @Nullable StatusBarManagerInternal mStatusBar;
     Vibrator mVibrator;
     private VrManagerInternal mVrManagerInternal;
-    private WindowManagerInternal mWindowManagerInternal;
 
     final IBinder mForegroundToken = new Binder();
     private Handler mHandler;
@@ -454,15 +452,13 @@
         final String pkg;
         final ITransientNotification callback;
         int duration;
-        Binder token;
 
-        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
-                    Binder token) {
+        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
+        {
             this.pid = pid;
             this.pkg = pkg;
             this.callback = callback;
             this.duration = duration;
-            this.token = token;
         }
 
         void update(int duration) {
@@ -1129,7 +1125,6 @@
             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
             mVrManagerInternal = getLocalService(VrManagerInternal.class);
-            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
             mZenModeHelper.onSystemReady();
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             // This observer will force an update when observe is called, causing us to
@@ -1330,13 +1325,10 @@
                             }
                         }
 
-                        Binder token = new Binder();
-                        mWindowManagerInternal.addWindowToken(token,
-                                WindowManager.LayoutParams.TYPE_TOAST);
-                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
+                        record = new ToastRecord(callingPid, pkg, callback, duration);
                         mToastQueue.add(record);
                         index = mToastQueue.size() - 1;
-                        keepProcessAliveIfNeededLocked(callingPid);
+                        keepProcessAliveLocked(callingPid);
                     }
                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
                     // new or just been updated.  Call back and tell it to show itself.
@@ -2995,7 +2987,7 @@
         while (record != null) {
             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
             try {
-                record.callback.show(record.token);
+                record.callback.show();
                 scheduleTimeoutLocked(record);
                 return;
             } catch (RemoteException e) {
@@ -3006,7 +2998,7 @@
                 if (index >= 0) {
                     mToastQueue.remove(index);
                 }
-                keepProcessAliveIfNeededLocked(record.pid);
+                keepProcessAliveLocked(record.pid);
                 if (mToastQueue.size() > 0) {
                     record = mToastQueue.get(0);
                 } else {
@@ -3026,11 +3018,8 @@
             // don't worry about this, we're about to remove it from
             // the list anyway
         }
-
-        ToastRecord lastToast = mToastQueue.remove(index);
-        mWindowManagerInternal.removeWindowToken(lastToast.token, true);
-
-        keepProcessAliveIfNeededLocked(record.pid);
+        mToastQueue.remove(index);
+        keepProcessAliveLocked(record.pid);
         if (mToastQueue.size() > 0) {
             // Show the next one. If the callback fails, this will remove
             // it from the list, so don't assume that the list hasn't changed
@@ -3074,7 +3063,7 @@
     }
 
     // lock on mToastQueue
-    void keepProcessAliveIfNeededLocked(int pid)
+    void keepProcessAliveLocked(int pid)
     {
         int toastCount = 0; // toasts from this pid
         ArrayList<ToastRecord> list = mToastQueue;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6253963..e502764 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -301,9 +301,6 @@
     /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
     static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
 
-    /** Amount of time (in milliseconds) a toast window can be shown. */
-    public static final int TOAST_WINDOW_TIMEOUT = 3500; // 3.5 seconds
-
     /**
      * Lock protecting internal state.  Must not call out into window
      * manager with lock held.  (This lock will be acquired in places
@@ -2232,18 +2229,6 @@
                     attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
                 }
                 break;
-
-            case TYPE_TOAST:
-                // While apps should use the dedicated toast APIs to add such windows
-                // it possible legacy apps to add the window directly. Therefore, we
-                // make windows added directly by the app behave as a toast as much
-                // as possible in terms of timeout and animation.
-                if (attrs.hideTimeoutMilliseconds < 0
-                        || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
-                    attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
-                }
-                attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
-                break;
         }
 
         if (attrs.type != TYPE_STATUS_BAR) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 70a1ee6..6451c74 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -35,7 +35,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -201,7 +200,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
@@ -1869,7 +1867,6 @@
         boolean reportNewConfig = false;
         WindowState attachedWindow = null;
         long origId;
-        final int callingUid = Binder.getCallingUid();
         final int type = attrs.type;
 
         synchronized(mWindowMap) {
@@ -1917,8 +1914,6 @@
             boolean addToken = false;
             WindowToken token = mTokenMap.get(attrs.token);
             AppWindowToken atoken = null;
-            boolean addToastWindowRequiresToken = false;
-
             if (token == null) {
                 if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                     Slog.w(TAG_WM, "Attempted to add application window with unknown token "
@@ -1955,15 +1950,6 @@
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-                if (type == TYPE_TOAST) {
-                    // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
-                    if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
-                            attachedWindow)) {
-                        Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
-                                + attrs.token + ".  Aborting.");
-                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
-                    }
-                }
                 token = new WindowToken(this, attrs.token, -1, false);
                 addToken = true;
             } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
@@ -2013,15 +1999,6 @@
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-            } else if (type == TYPE_TOAST) {
-                // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
-                addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
-                        callingUid, attachedWindow);
-                if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
-                    Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
-                            + attrs.token + ".  Aborting.");
-                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
-                }
             } else if (type == TYPE_QS_DIALOG) {
                 if (token.windowType != TYPE_QS_DIALOG) {
                     Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
@@ -2066,35 +2043,6 @@
                 win.openInputChannel(outInputChannel);
             }
 
-            // If adding a toast requires a token for this app we always schedule hiding
-            // toast windows to make sure they don't stick around longer then necessary.
-            // We hide instead of remove such windows as apps aren't prepared to handle
-            // windows being removed under them.
-            //   If the app is older it can add toasts without a token and hence overlay
-            // other apps. To be maximally compatible with these apps we will hide the
-            // window after the toast timeout only if the focused window is from another
-            // UID, otherwise we allow unlimited duration. When a UID looses focus we
-            // schedule hiding all of its toast windows.
-            if (type == TYPE_TOAST) {
-                if (!canAddToastWindowForUid(getDefaultDisplayContentLocked(), callingUid)) {
-                    Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
-                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
-                }
-                // Make sure this happens before we moved focus as one can make the
-                // toast focusable to force it not being hidden after the timeout.
-                // Focusable toasts are always timed out to prevent a focused app to
-                // show a focusable toasts while it has focus which will be kept on
-                // the screen after the activity goes away.
-                if (addToastWindowRequiresToken
-                        || (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0
-                        || mCurrentFocus == null
-                        || mCurrentFocus.mOwnerUid != callingUid) {
-                    mH.sendMessageDelayed(
-                            mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
-                            win.mAttrs.hideTimeoutMilliseconds);
-                }
-            }
-
             // From now on, no exceptions or errors allowed!
 
             res = WindowManagerGlobal.ADD_OKAY;
@@ -2233,6 +2181,11 @@
             if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
                 reportNewConfig = true;
             }
+            if (attrs.removeTimeoutMilliseconds > 0) {
+                mH.sendMessageDelayed(
+                        mH.obtainMessage(H.WINDOW_REMOVE_TIMEOUT, win),
+                        attrs.removeTimeoutMilliseconds);
+            }
         }
 
         if (reportNewConfig) {
@@ -2244,73 +2197,6 @@
         return res;
     }
 
-    private boolean canAddToastWindowForUid(DisplayContent displayContent, int uid) {
-        // We allow one toast window per UID being shown at a time.
-        WindowList windows = displayContent.getWindowList();
-        final int windowCount = windows.size();
-        for (int i = 0; i < windowCount; i++) {
-            WindowState window = windows.get(i);
-            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid
-                    && !window.mPermanentlyHidden) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean doesAddToastWindowRequireToken(String packageName, int callingUid,
-            WindowState attachedWindow) {
-        // Try using the target SDK of the root window
-        if (attachedWindow != null) {
-            WindowState currentWindow = attachedWindow;
-            while (currentWindow != null) {
-                if (currentWindow.mAppToken != null
-                        && currentWindow.mAppToken.targetSdk > Build.VERSION_CODES.N_MR1) {
-                    return true;
-                }
-                currentWindow = currentWindow.mAttachedWindow;
-            }
-        } else {
-            // Otherwise, look at the package
-            try {
-                ApplicationInfo appInfo = mContext.getPackageManager()
-                        .getApplicationInfoAsUser(packageName, 0,
-                                UserHandle.getUserId(callingUid));
-                if (appInfo.uid != callingUid) {
-                    throw new SecurityException("Package " + packageName + " not in UID "
-                            + callingUid);
-                }
-                if (appInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
-                    return true;
-                }
-            } catch (PackageManager.NameNotFoundException e) {
-                /* ignore */
-            }
-        }
-        return false;
-    }
-
-    private void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus,
-            WindowState newFocus) {
-        if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) {
-            return;
-        }
-        final int lostFocusUid = oldFocus.mOwnerUid;
-        DisplayContent displayContent = oldFocus.getDisplayContent();
-        WindowList windows = displayContent.getWindowList();
-        final int windowCount = windows.size();
-        for (int i = 0; i < windowCount; i++) {
-            WindowState window = windows.get(i);
-            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == lostFocusUid) {
-                if (!mH.hasMessages(H.WINDOW_HIDE_TIMEOUT, window)) {
-                    mH.sendMessageDelayed(
-                            mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, window),
-                            window.mAttrs.hideTimeoutMilliseconds);
-                }
-            }
-        }
-    }
-
     /**
      * Returns true if we're done setting up any transitions.
      */
@@ -8238,7 +8124,7 @@
         public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
         public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
         public static final int UPDATE_ANIMATION_SCALE = 51;
-        public static final int WINDOW_HIDE_TIMEOUT = 52;
+        public static final int WINDOW_REMOVE_TIMEOUT = 52;
         public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
 
@@ -8858,7 +8744,7 @@
                     mAmInternal.notifyStartingWindowDrawn();
                 }
                 break;
-                case WINDOW_HIDE_TIMEOUT: {
+                case WINDOW_REMOVE_TIMEOUT: {
                     final WindowState window = (WindowState) msg.obj;
                     synchronized(mWindowMap) {
                         // TODO: This is all about fixing b/21693547
@@ -8869,11 +8755,8 @@
                         // running under debugger) to crash (b/29105388). The windows will
                         // eventually be removed when the client process finishes.
                         // The best we can do for now is remove the FLAG_KEEP_SCREEN_ON
-                        // and prevent the symptoms of b/21693547. Since apps don't
-                        // support windows being removed under them we hide the window
-                        // and it will be removed when the app dies.
+                        // and prevent the symptoms of b/21693547.
                         window.mAttrs.flags &= ~FLAG_KEEP_SCREEN_ON;
-                        window.markPermanentlyHiddenLw();
                         window.setDisplayLayoutNeeded();
                         mWindowPlacerLocked.performSurfacePlacement();
                     }
@@ -9903,11 +9786,6 @@
 
             adjustForImeIfNeeded(displayContent);
 
-            // We may need to schedule some toast windows to be removed. The
-            // toasts for an app that does not have input focus are removed
-            // within a timeout to prevent apps to redress other apps' UI.
-            scheduleToastWindowsTimeoutIfNeededLocked(oldFocus, newFocus);
-
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
             return true;
         }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 10f01e4..a00ac5d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -165,7 +165,6 @@
     boolean mPolicyVisibility = true;
     boolean mPolicyVisibilityAfterAnim = true;
     boolean mAppOpVisibility = true;
-    boolean mPermanentlyHidden;
     boolean mAppFreezing;
     boolean mAttachedHidden;    // is our parent window hidden?
     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
@@ -1874,11 +1873,6 @@
             // Being hidden due to app op request.
             return false;
         }
-        if (mPermanentlyHidden) {
-            // Permanently hidden until the app exists as apps aren't prepared
-            // to handle their windows being removed from under them.
-            return false;
-        }
         if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
             // Already showing.
             return false;
@@ -1969,13 +1963,6 @@
         }
     }
 
-    public void markPermanentlyHiddenLw() {
-        if (!mPermanentlyHidden) {
-            mPermanentlyHidden = true;
-            hideLw(true, true);
-        }
-    }
-
     public void pokeDrawLockLw(long timeout) {
         if (isVisibleOrAdding()) {
             if (mDrawLock == null) {
@@ -2625,7 +2612,7 @@
             pw.println(Integer.toHexString(mSystemUiVisibility));
         }
         if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
-                || mAttachedHidden || mPermanentlyHidden) {
+                || mAttachedHidden) {
             pw.print(prefix); pw.print("mPolicyVisibility=");
                     pw.print(mPolicyVisibility);
                     pw.print(" mPolicyVisibilityAfterAnim=");
@@ -2633,7 +2620,6 @@
                     pw.print(" mAppOpVisibility=");
                     pw.print(mAppOpVisibility);
                     pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
-                    pw.print(" mPermanentlyHidden="); pw.println(mPermanentlyHidden);
         }
         if (!mRelayoutCalled || mLayoutNeeded) {
             pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 407d315..1a9d2f2 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -45,7 +45,9 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -109,6 +111,11 @@
     private final byte[] mRA = new byte[IPV6_MIN_MTU];
     @GuardedBy("mLock")
     private int mRaLength;
+    @GuardedBy("mLock")
+    private final HashMap<IpPrefix, Integer> mDeprecatedPrefixes;
+
+    @GuardedBy("mLock")
+    private RaParams mRaParams;
 
     private volatile FileDescriptor mSocket;
     private volatile MulticastTransmitter mMulticastTransmitter;
@@ -141,45 +148,29 @@
         mIfIndex = ifindex;
         mHwAddr = hwaddr;
         mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mIfIndex), 0);
+        mDeprecatedPrefixes = new HashMap<>();
     }
 
-    public void buildNewRa(RaParams params) {
+    public void buildNewRa(RaParams params, HashSet<IpPrefix> newlyDeprecated) {
+        if (newlyDeprecated != null) {
+            synchronized (mLock) {
+                for (IpPrefix ipp : newlyDeprecated) {
+                    mDeprecatedPrefixes.put(ipp, MAX_URGENT_RTR_ADVERTISEMENTS);
+                }
+            }
+        }
+
+        // TODO: Send MAX_URGENT_RTR_ADVERTISEMENTS zero router lifetime RAs,
+        // iff. we have already sent an RA.
         if (params == null || params.prefixes.isEmpty()) {
             // No RA to be served at this time.
             clearRa();
             return;
         }
 
-        if (params.mtu < IPV6_MIN_MTU) {
-            params.mtu = IPV6_MIN_MTU;
-        }
-
-        final ByteBuffer ra = ByteBuffer.wrap(mRA);
-        ra.order(ByteOrder.BIG_ENDIAN);
-
         synchronized (mLock) {
-            try {
-                putHeader(ra, params.hasDefaultRoute);
-                putSlla(ra, mHwAddr);
-                // https://tools.ietf.org/html/rfc5175#section-4 says:
-                //
-                //     "MUST NOT be added to a Router Advertisement message
-                //      if no flags in the option are set."
-                //
-                // putExpandedFlagsOption(ra);
-                putMtu(ra, params.mtu);
-                for (IpPrefix ipp : params.prefixes) {
-                    putPio(ra, ipp);
-                }
-                if (params.dnses.size() > 0) {
-                    putRdnss(ra, params.dnses);
-                }
-                mRaLength = ra.position();
-            } catch (BufferOverflowException e) {
-                Log.e(TAG, "Could not construct new RA: " + e);
-                mRaLength = 0;
-                return;
-            }
+            mRaParams = params;
+            assembleRa();
         }
 
         maybeNotifyMulticastTransmitter();
@@ -216,6 +207,64 @@
         }
     }
 
+    private void assembleRa() {
+        final ByteBuffer ra = ByteBuffer.wrap(mRA);
+        ra.order(ByteOrder.BIG_ENDIAN);
+
+        synchronized (mLock) {
+            try {
+                putHeader(ra, mRaParams.hasDefaultRoute);
+
+                putSlla(ra, mHwAddr);
+
+                // https://tools.ietf.org/html/rfc5175#section-4 says:
+                //
+                //     "MUST NOT be added to a Router Advertisement message
+                //      if no flags in the option are set."
+                //
+                // putExpandedFlagsOption(ra);
+
+                putMtu(ra, mRaParams.mtu);
+
+                for (IpPrefix ipp : mRaParams.prefixes) {
+                    putPio(ra, ipp, DEFAULT_LIFETIME, DEFAULT_LIFETIME);
+                    mDeprecatedPrefixes.remove(ipp);
+                }
+
+                for (IpPrefix ipp : mDeprecatedPrefixes.keySet()) {
+                    putPio(ra, ipp, 0, 0);
+                }
+
+                if (mRaParams.dnses.size() > 0) {
+                    putRdnss(ra, mRaParams.dnses);
+                }
+
+                mRaLength = ra.position();
+            } catch (BufferOverflowException e) {
+                Log.e(TAG, "Could not construct new RA: " + e);
+                mRaLength = 0;
+                return;
+            }
+        }
+    }
+
+    private int decrementDeprecatedPrefixes() {
+        int removed = 0;
+
+        synchronized (mLock) {
+            for (Map.Entry<IpPrefix, Integer> kv : mDeprecatedPrefixes.entrySet()) {
+                if (kv.getValue() == 0) {
+                    mDeprecatedPrefixes.remove(kv.getKey());
+                    removed++;
+                } else {
+                    kv.setValue(kv.getValue() - 1);
+                }
+            }
+        }
+
+        return removed;
+    }
+
     private void maybeNotifyMulticastTransmitter() {
         final MulticastTransmitter m = mMulticastTransmitter;
         if (m != null) {
@@ -325,10 +374,11 @@
         ra.put(ND_OPTION_MTU)
           .put(MTU_NUM_8OCTETS)
           .putShort(asShort(0))
-          .putInt(mtu);
+          .putInt((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu);
     }
 
-    private static void putPio(ByteBuffer ra, IpPrefix ipp) {
+    private static void putPio(ByteBuffer ra, IpPrefix ipp,
+                               int validTime, int preferredTime) {
         /**
             Prefix Information
 
@@ -359,13 +409,17 @@
         final byte ND_OPTION_PIO = 3;
         final byte PIO_NUM_8OCTETS = 4;
 
+        if (validTime < 0) validTime = 0;
+        if (preferredTime < 0) preferredTime = 0;
+        if (preferredTime > validTime) preferredTime = validTime;
+
         final byte[] addr = ipp.getAddress().getAddress();
         ra.put(ND_OPTION_PIO)
           .put(PIO_NUM_8OCTETS)
           .put(asByte(prefixLength))
-          .put(asByte(0xc0))  // L&A set
-          .putInt(DEFAULT_LIFETIME)
-          .putInt(DEFAULT_LIFETIME)
+          .put(asByte(0xc0)) /* L & A set */
+          .putInt(validTime)
+          .putInt(preferredTime)
           .putInt(0)
           .put(addr);
     }
@@ -547,6 +601,11 @@
                 }
 
                 maybeSendRA(mAllNodes);
+                if (decrementDeprecatedPrefixes() > 0) {
+                    // At least one deprecated PIO has been removed;
+                    // reassemble the RA.
+                    assembleRa();
+                }
             }
         }
 
@@ -560,15 +619,17 @@
         }
 
         private int getNextMulticastTransmitDelaySec() {
+            int countDeprecatedPrefixes = 0;
             synchronized (mLock) {
                 if (mRaLength < MIN_RA_HEADER_SIZE) {
                     // No actual RA to send; just sleep for 1 day.
                     return DAY_IN_SECONDS;
                 }
+                countDeprecatedPrefixes = mDeprecatedPrefixes.size();
             }
 
             final int urgentPending = mUrgentAnnouncements.getAndDecrement();
-            if (urgentPending > 0) {
+            if (urgentPending > 0 || countDeprecatedPrefixes > 0) {
                 return MIN_DELAY_BETWEEN_RAS_SEC;
             }
 
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 2346f85..16a0def 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -574,6 +574,7 @@
             mLaunchIntent = intent;
             mForceStopBeforeLaunch = forceStopBeforeLaunch;
             mLaunchReason = launchReason;
+            mResult = -1L;
         }
 
         public Long getResult() {
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 9976d00..59da467 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -529,6 +529,16 @@
     int openGLESVersion;
 };
 
+static bool hasFeature(const char* name, const FeatureGroup& grp,
+                       const KeyedVector<String8, ImpliedFeature>& implied) {
+    String8 name8(name);
+    ssize_t idx = grp.features.indexOfKey(name8);
+    if (idx < 0) {
+        idx = implied.indexOfKey(name8);
+    }
+    return idx >= 0;
+}
+
 static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
                               const char* name, const char* reason, bool sdk23) {
     String8 name8(name);
@@ -616,9 +626,16 @@
     } else if (name == "android.hardware.location.gps" ||
             name == "android.hardware.location.network") {
         grp->features.add(String8("android.hardware.location"), Feature(true));
+    } else if (name == "android.hardware.faketouch.multitouch") {
+        grp->features.add(String8("android.hardware.faketouch"), Feature(true));
+    } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
+            name == "android.hardware.faketouch.multitouch.jazzhands") {
+        grp->features.add(String8("android.hardware.faketouch.multitouch"), Feature(true));
+        grp->features.add(String8("android.hardware.faketouch"), Feature(true));
     } else if (name == "android.hardware.touchscreen.multitouch") {
         grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
-    } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
+    } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
+            name == "android.hardware.touchscreen.multitouch.jazzhands") {
         grp->features.add(String8("android.hardware.touchscreen.multitouch"), Feature(true));
         grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
     } else if (name == "android.hardware.opengles.aep") {
@@ -2005,8 +2022,12 @@
                 }
             }
 
-            addImpliedFeature(&impliedFeatures, "android.hardware.touchscreen",
-                    "default feature for all apps", false);
+            // If the app hasn't declared the touchscreen as a feature requirement (either
+            // directly or implied, required or not), then the faketouch feature is implied.
+            if (!hasFeature("android.hardware.touchscreen", commonFeatures, impliedFeatures)) {
+                addImpliedFeature(&impliedFeatures, "android.hardware.faketouch",
+                                  "default feature for all apps", false);
+            }
 
             const size_t numFeatureGroups = featureGroups.size();
             if (numFeatureGroups == 0) {