Merge "Set always opaque flag on CarNavigationBar."
diff --git a/Android.mk b/Android.mk
index 47efddd..6831945 100644
--- a/Android.mk
+++ b/Android.mk
@@ -924,6 +924,7 @@
 
 LOCAL_DROIDDOC_OPTIONS:=\
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-referenceonly \
 		-api $(INTERNAL_PLATFORM_API_FILE) \
 		-removedApi $(INTERNAL_PLATFORM_REMOVED_API_FILE) \
 		-nodocs
@@ -957,6 +958,7 @@
 
 LOCAL_DROIDDOC_OPTIONS:=\
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-referenceonly \
 		-showAnnotation android.annotation.SystemApi \
 		-api $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
 		-removedApi $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) \
@@ -991,6 +993,7 @@
 
 LOCAL_DROIDDOC_OPTIONS:=\
                $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+               -referenceonly \
                -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_test_stubs_current_intermediates/src \
                -showAnnotation android.annotation.TestApi \
                -api $(INTERNAL_PLATFORM_TEST_API_FILE) \
@@ -1024,6 +1027,7 @@
 
 LOCAL_DROIDDOC_OPTIONS:=\
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-referenceonly \
 		-parsecomments
 
 LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
@@ -1062,7 +1066,7 @@
 		-sdkvalues $(OUT_DOCS) \
 		-hdf android.whichdoc offline
 
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
 include $(BUILD_DROIDDOC)
 
@@ -1099,7 +1103,7 @@
 		-hdf android.whichdoc offline \
 		-referenceonly
 
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
 include $(BUILD_DROIDDOC)
 
@@ -1135,7 +1139,7 @@
 		-hdf android.hasSamples true \
 		-samplesdir $(samples_dir)
 
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
 include $(BUILD_DROIDDOC)
 
@@ -1159,6 +1163,7 @@
 
 LOCAL_DROIDDOC_OPTIONS:= \
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-referenceonly \
 		-showAnnotation android.annotation.SystemApi \
 		-title "Android SDK - Including system APIs." \
 		-toroot / \
@@ -1202,7 +1207,7 @@
 		-hdf android.hasSamples true \
 		-samplesdir $(samples_dir)
 
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
 include $(BUILD_DROIDDOC)
 
@@ -1230,7 +1235,7 @@
 		-devsite \
 		-ignoreJdLinks
 
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
 include $(BUILD_DROIDDOC)
 
@@ -1255,11 +1260,10 @@
 		-toroot / \
 		-hdf android.whichdoc online \
 		$(sample_groups) \
-		-useUpdatedTemplates \
 		-hdf android.hasSamples true \
 		-samplesdir $(samples_dir)
 
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
 include $(BUILD_DROIDDOC)
 
@@ -1278,6 +1282,7 @@
 LOCAL_MODULE := hidden
 LOCAL_DROIDDOC_OPTIONS:=\
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-referenceonly \
 		-title "Android SDK - Including hidden APIs."
 #		-hidden
 
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index d43b8c5..c7474a11 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -72,59 +72,64 @@
 public class Content {
 
     private static final String USAGE =
-        "usage: adb shell content [subcommand] [options]\n"
-        + "\n"
-        + "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
-                + " --bind <BINDING> [--bind <BINDING>...]\n"
-        + "  <URI> a content provider URI.\n"
-        + "  <BINDING> binds a typed value to a column and is formatted:\n"
-        + "  <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
-        + "  <TYPE> specifies data type such as:\n"
-        + "  b - boolean, s - string, i - integer, l - long, f - float, d - double\n"
-        + "  Note: Omit the value for passing an empty string, e.g column:s:\n"
-        + "  Example:\n"
-        + "  # Add \"new_setting\" secure setting with value \"new_value\".\n"
-        + "  adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
-                + " --bind value:s:new_value\n"
-        + "\n"
-        + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n"
-        + "  <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
-                + " - see example below).\n"
-        + "  Example:\n"
-        + "  # Change \"new_setting\" secure setting to \"newer_value\".\n"
-        + "  adb shell content update --uri content://settings/secure --bind"
-                + " value:s:newer_value --where \"name=\'new_setting\'\"\n"
-        + "\n"
-        + "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
-                + " [--bind <BINDING>...] [--where <WHERE>]\n"
-        + "  Example:\n"
-        + "  # Remove \"new_setting\" secure setting.\n"
-        + "  adb shell content delete --uri content://settings/secure "
-                + "--where \"name=\'new_setting\'\"\n"
-        + "\n"
-        + "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
-                + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
-        + "  <PROJECTION> is a list of colon separated column names and is formatted:\n"
-        + "  <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
-        + "  <SORT_ORDER> is the order in which rows in the result should be sorted.\n"
-        + "  Example:\n"
-        + "  # Select \"name\" and \"value\" columns from secure settings where \"name\" is "
-                + "equal to \"new_setting\" and sort the result by name in ascending order.\n"
-        + "  adb shell content query --uri content://settings/secure --projection name:value"
-                + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n"
-        + "\n"
-        + "usage: adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]\n"
-        + "       [--extra <BINDING> ...]\n"
-        + "  <METHOD> is the name of a provider-defined method\n"
-        + "  <ARG> is an optional string argument\n"
-        + "  <BINDING> is like --bind above, typed data of the form <KEY>:{b,s,i,l,f,d}:<VAL>\n"
-        + "\n"
-        + "usage: adb shell content read --uri <URI> [--user <USER_ID>]\n"
-        + "  Example:\n"
-        + "  # cat default ringtone to a file, then pull to host\n"
-        + "  adb shell 'content read --uri content://settings/system/ringtone >"
-                + " /mnt/sdcard/tmp.ogg' && adb pull /mnt/sdcard/tmp.ogg\n"
-        + "\n";
+            "usage: adb shell content [subcommand] [options]\n"
+                    + "\n"
+                    + "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
+                    + " --bind <BINDING> [--bind <BINDING>...]\n"
+                    + "  <URI> a content provider URI.\n"
+                    + "  <BINDING> binds a typed value to a column and is formatted:\n"
+                    + "  <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
+                    + "  <TYPE> specifies data type such as:\n"
+                    + "  b - boolean, s - string, i - integer, l - long, f - float, d - double\n"
+                    + "  Note: Omit the value for passing an empty string, e.g column:s:\n"
+                    + "  Example:\n"
+                    + "  # Add \"new_setting\" secure setting with value \"new_value\".\n"
+                    + "  adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
+                    + " --bind value:s:new_value\n"
+                    + "\n"
+                    + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n"
+                    + "  <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
+                    + " - see example below).\n"
+                    + "  Example:\n"
+                    + "  # Change \"new_setting\" secure setting to \"newer_value\".\n"
+                    + "  adb shell content update --uri content://settings/secure --bind"
+                    + " value:s:newer_value --where \"name=\'new_setting\'\"\n"
+                    + "\n"
+                    + "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
+                    + " [--bind <BINDING>...] [--where <WHERE>]\n"
+                    + "  Example:\n"
+                    + "  # Remove \"new_setting\" secure setting.\n"
+                    + "  adb shell content delete --uri content://settings/secure "
+                    + "--where \"name=\'new_setting\'\"\n"
+                    + "\n"
+                    + "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
+                    + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
+                    + "  <PROJECTION> is a list of colon separated column names and is formatted:\n"
+                    + "  <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
+                    + "  <SORT_ORDER> is the order in which rows in the result should be sorted.\n"
+                    + "  Example:\n"
+                    + "  # Select \"name\" and \"value\" columns from secure settings where \"name\" is "
+                    + "equal to \"new_setting\" and sort the result by name in ascending order.\n"
+                    + "  adb shell content query --uri content://settings/secure --projection name:value"
+                    + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n"
+                    + "\n"
+                    + "usage: adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]\n"
+                    + "       [--extra <BINDING> ...]\n"
+                    + "  <METHOD> is the name of a provider-defined method\n"
+                    + "  <ARG> is an optional string argument\n"
+                    + "  <BINDING> is like --bind above, typed data of the form <KEY>:{b,s,i,l,f,d}:<VAL>\n"
+                    + "\n"
+                    + "usage: adb shell content read --uri <URI> [--user <USER_ID>]\n"
+                    + "  Example:\n"
+                    + "  # cat default ringtone to a file, then pull to host\n"
+                    + "  adb shell 'content read --uri content://settings/system/ringtone >"
+                    + " /mnt/sdcard/tmp.ogg' && adb pull /mnt/sdcard/tmp.ogg\n"
+                    + "\n"
+                    + "usage: adb shell content gettype --uri <URI> [--user <USER_ID>]\n"
+                    + "  Example:\n"
+                    + "  # Show the mime-type of the URI\n"
+                    + "  adb shell content gettype --uri content://media/internal/audio/media/\n"
+                    + "\n";
 
     private static class Parser {
         private static final String ARGUMENT_INSERT = "insert";
@@ -133,6 +138,7 @@
         private static final String ARGUMENT_QUERY = "query";
         private static final String ARGUMENT_CALL = "call";
         private static final String ARGUMENT_READ = "read";
+        private static final String ARGUMENT_GET_TYPE = "gettype";
         private static final String ARGUMENT_WHERE = "--where";
         private static final String ARGUMENT_BIND = "--bind";
         private static final String ARGUMENT_URI = "--uri";
@@ -172,6 +178,8 @@
                     return parseCallCommand();
                 } else if (ARGUMENT_READ.equals(operation)) {
                     return parseReadCommand();
+                } else if (ARGUMENT_GET_TYPE.equals(operation)) {
+                    return parseGetTypeCommand();
                 } else {
                     throw new IllegalArgumentException("Unsupported operation: " + operation);
                 }
@@ -291,6 +299,26 @@
             return new CallCommand(uri, userId, method, arg, values);
         }
 
+        private GetTypeCommand parseGetTypeCommand() {
+            Uri uri = null;
+            int userId = UserHandle.USER_SYSTEM;
+
+            for (String argument; (argument = mTokenizer.nextArg()) != null;) {
+                if (ARGUMENT_URI.equals(argument)) {
+                    uri = Uri.parse(argumentValueRequired(argument));
+                } else if (ARGUMENT_USER.equals(argument)) {
+                    userId = Integer.parseInt(argumentValueRequired(argument));
+                } else {
+                    throw new IllegalArgumentException("Unsupported argument: " + argument);
+                }
+            }
+            if (uri == null) {
+                throw new IllegalArgumentException("Content provider URI not specified."
+                        + " Did you specify --uri argument?");
+            }
+            return new GetTypeCommand(uri, userId);
+        }
+
         private ReadCommand parseReadCommand() {
             Uri uri = null;
             int userId = UserHandle.USER_SYSTEM;
@@ -511,6 +539,18 @@
         }
     }
 
+    private static class GetTypeCommand extends Command {
+        public GetTypeCommand(Uri uri, int userId) {
+            super(uri, userId);
+        }
+
+        @Override
+        public void onExecute(IContentProvider provider) throws Exception {
+            String type = provider.getType(mUri);
+            System.out.println("Result: " + type);
+        }
+    }
+
     private static class ReadCommand extends Command {
         public ReadCommand(Uri uri, int userId) {
             super(uri, userId);
diff --git a/core/java/android/app/ITransientNotification.aidl b/core/java/android/app/ITransientNotification.aidl
index 35b53a4..d5b3ed0 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();
+    void show(IBinder windowToken);
     void hide();
 }
 
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ad3f4d2..c6338cb 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -266,7 +266,6 @@
     InputMethodManager mImm;
     
     int mTheme = 0;
-    boolean mHardwareAccelerated = false;
     
     LayoutInflater mInflater;
     TypedArray mThemeAttrs;
@@ -752,27 +751,27 @@
     }
 
     /**
-     * You can call this to try to enable hardware accelerated drawing for
-     * your IME. This must be set before {@link #onCreate}, so you
-     * will typically call it in your constructor.  It is not always possible
-     * to use hardware accelerated drawing in an IME (for example on low-end
-     * devices that do not have the resources to support this), so the call
-     * returns true if it succeeds otherwise false if you will need to draw
-     * in software.  You must be able to handle either case.
+     * You can call this to try to enable accelerated drawing for your IME. This must be set before
+     * {@link #onCreate()}, so you will typically call it in your constructor.  It is not always
+     * possible to use hardware accelerated drawing in an IME (for example on low-end devices that
+     * do not have the resources to support this), so the call {@code true} if it succeeds otherwise
+     * {@code false} if you will need to draw in software.  You must be able to handle either case.
      *
-     * @deprecated Starting in API 21, hardware acceleration is always enabled
-     *             on capable devices.
+     * <p>In API 21 and later, system may automatically enable hardware accelerated drawing for your
+     * IME on capable devices even if this method is not explicitly called. Make sure that your IME
+     * is able to handle either case.</p>
+     *
+     * @return {@code true} if accelerated drawing is successfully enabled otherwise {@code false}.
+     *         On API 21 and later devices the return value is basically just a hint and your IME
+     *         does not need to change the behavior based on the it
+     * @deprecated Starting in API 21, hardware acceleration is always enabled on capable devices
      */
     @Deprecated
     public boolean enableHardwareAcceleration() {
         if (mWindow != null) {
             throw new IllegalStateException("Must be called before onCreate()");
         }
-        if (ActivityManager.isHighEndGfx()) {
-            mHardwareAccelerated = true;
-            return true;
-        }
-        return false;
+        return ActivityManager.isHighEndGfx();
     }
 
     @Override public void onCreate() {
@@ -793,9 +792,6 @@
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
                 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
-        if (mHardwareAccelerated) {
-            mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
-        }
         initViews();
         mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
     }
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 224ff5b..495340d 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -58,10 +58,6 @@
     /** Callback used to change internal state on tethering */
     void onTetheringChanged(String iface, boolean tethering);
 
-    /** Control which applications can be exempt from background data restrictions */
-    void addRestrictBackgroundWhitelistedUid(int uid);
-    void removeRestrictBackgroundWhitelistedUid(int uid);
-    int[] getRestrictBackgroundWhitelistedUids();
     /** Gets the restrict background status based on the caller's UID:
         1 - disabled
         2 - whitelisted
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b05f3c2..0ee0fc9 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6406,6 +6406,21 @@
         public static final String WEB_ACTION_ENABLED = "web_action_enabled";
 
         /**
+         * The uptime when tasks were last persisted.  This is used to adjust the previous task
+         * active times to be relative to the current boot time.
+         * @hide
+         */
+        public static final String TASK_PERSISTER_LAST_WRITE_UPTIME = "task_persister_write_uptime";
+
+        /**
+         * Used by Overview to keep track of the last visible task's active time to determine what
+         * should tasks be visible.
+         * @hide
+         */
+        public static final String OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME =
+                "overview_last_visible_task_active_uptime";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/security/net/config/DirectoryCertificateSource.java b/core/java/android/security/net/config/DirectoryCertificateSource.java
index e3c9d65..119f5d0 100644
--- a/core/java/android/security/net/config/DirectoryCertificateSource.java
+++ b/core/java/android/security/net/config/DirectoryCertificateSource.java
@@ -19,6 +19,7 @@
 import android.os.Environment;
 import android.os.UserHandle;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.Pair;
 import java.io.BufferedInputStream;
 import java.io.File;
@@ -44,6 +45,7 @@
  * @hide
  */
 abstract class DirectoryCertificateSource implements CertificateSource {
+    private static final String LOG_TAG = "DirectoryCertificateSrc";
     private final File mDir;
     private final Object mLock = new Object();
     private final CertificateFactory mCertFactory;
@@ -149,6 +151,9 @@
                 continue;
             }
             X509Certificate cert = readCertificate(fileName);
+            if (cert == null) {
+                continue;
+            }
             if (!subj.equals(cert.getSubjectX500Principal())) {
                 continue;
             }
@@ -173,6 +178,9 @@
                 continue;
             }
             X509Certificate cert = readCertificate(fileName);
+            if (cert == null) {
+                continue;
+            }
             if (!subj.equals(cert.getSubjectX500Principal())) {
                 continue;
             }
@@ -194,6 +202,7 @@
             is = new BufferedInputStream(new FileInputStream(new File(mDir, file)));
             return (X509Certificate) mCertFactory.generateCertificate(is);
         } catch (CertificateException | IOException e) {
+            Log.e(LOG_TAG, "Failed to read certificate from " + file, e);
             return null;
         } finally {
             IoUtils.closeQuietly(is);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index dccc1b2..12ac7cf 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -227,6 +227,7 @@
         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/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d786eaf..ece0e1b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2167,7 +2167,12 @@
         }
 
         if (changedVisibility || regainedFocus) {
-            host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+            // Toasts are presented as notifications - don't present them as windows as well
+            boolean isToast = (mWindowAttributes == null) ? false
+                    : (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST);
+            if (!isToast) {
+                host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+            }
         }
 
         mFirst = false;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0dbf00d..395f738 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1752,14 +1752,18 @@
         public CharSequence accessibilityTitle;
 
         /**
-         * Sets a timeout in milliseconds before which the window will be removed
+         * Sets a timeout in milliseconds before which the window will be hidden
          * 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 removed. Must be specified at window creation time.
+         * 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.
          *
          * @hide
          */
-        public long removeTimeoutMilliseconds = -1;
+        public long hideTimeoutMilliseconds = -1;
 
         public LayoutParams() {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
@@ -1895,7 +1899,7 @@
             out.writeInt(needsMenuKey);
             out.writeInt(accessibilityIdOfAnchor);
             TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
-            out.writeLong(removeTimeoutMilliseconds);
+            out.writeLong(hideTimeoutMilliseconds);
         }
 
         public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1949,7 +1953,7 @@
             needsMenuKey = in.readInt();
             accessibilityIdOfAnchor = in.readInt();
             accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-            removeTimeoutMilliseconds = in.readLong();
+            hideTimeoutMilliseconds = in.readLong();
         }
 
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -2171,7 +2175,7 @@
             }
 
             // This can't change, it's only set at window creation time.
-            removeTimeoutMilliseconds = o.removeTimeoutMilliseconds;
+            hideTimeoutMilliseconds = o.hideTimeoutMilliseconds;
 
             return changes;
         }
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 07910b6..8023201 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -43,12 +43,14 @@
  *     in {@link android.os.Build.VERSION_CODES#HONEYCOMB}.</li>
  *     <li>{@link #requestCursorUpdates(int)}, which was introduced in
  *     {@link android.os.Build.VERSION_CODES#LOLLIPOP}.</li>
- *     <li>{@link #deleteSurroundingTextInCodePoints(int, int)}}, which
+ *     <li>{@link #deleteSurroundingTextInCodePoints(int, int)}, which
  *     was introduced in {@link android.os.Build.VERSION_CODES#N}.</li>
- *     <li>{@link #getHandler()}}, which was introduced in
+ *     <li>{@link #getHandler()}, which was introduced in
  *     {@link android.os.Build.VERSION_CODES#N}.</li>
- *     <li>{@link #closeConnection()}}, which was introduced in
+ *     <li>{@link #closeConnection()}, which was introduced in
  *     {@link android.os.Build.VERSION_CODES#N}.</li>
+ *     <li>{@link #commitContent(InputContentInfo, int, Bundle)}, which was
+ *     introduced in {@link android.os.Build.VERSION_CODES#N_MR1}.</li>
  * </ul>
  *
  * <h3>Implementing an IME or an editor</h3>
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6f3fa36..92ba408 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -741,9 +741,26 @@
     }
 
     /**
-     * Stores HTTP authentication credentials for a given host and realm. This
-     * method is intended to be used with
-     * {@link WebViewClient#onReceivedHttpAuthRequest}.
+     * Stores HTTP authentication credentials for a given host and realm to the {@link WebViewDatabase}
+     * instance.
+     * <p>
+     * To use HTTP authentication, the embedder application has to implement
+     * {@link WebViewClient#onReceivedHttpAuthRequest}, and call {@link HttpAuthHandler#proceed}
+     * with the correct username and password.
+     * <p>
+     * The embedder app can get the username and password any way it chooses, and does not have to
+     * use {@link WebViewDatabase}.
+     * <p>
+     * Notes:
+     * <li>
+     * {@link WebViewDatabase} is provided only as a convenience to store and retrieve http
+     * authentication credentials. WebView does not read from it during HTTP authentication.
+     * </li>
+     * <li>
+     * WebView does not provide a special mechanism to clear HTTP authentication credentials for
+     * implementing client logout. The client logout mechanism should be implemented by the Web site
+     * designer (such as server sending a HTTP 401 for invalidating credentials).
+     * </li>
      *
      * @param host the host to which the credentials apply
      * @param realm the realm to which the credentials apply
@@ -760,9 +777,8 @@
     }
 
     /**
-     * Retrieves HTTP authentication credentials for a given host and realm.
-     * This method is intended to be used with
-     * {@link WebViewClient#onReceivedHttpAuthRequest}.
+     * Retrieves HTTP authentication credentials for a given host and realm from the {@link
+     * WebViewDatabase} instance.
      *
      * @param host the host to which the credentials apply
      * @param realm the realm to which the credentials apply
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index cdff416..cc2c6cc 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -44,7 +44,7 @@
      *
      * @return true if there are any saved username/password pairs
      * @see WebView#savePassword
-     * @see #clearUsernamePassworda
+     * @see #clearUsernamePassword
      * @deprecated Saving passwords in WebView will not be supported in future versions.
      */
     @Deprecated
@@ -72,7 +72,16 @@
     public abstract boolean hasHttpAuthUsernamePassword();
 
     /**
-     * Clears any saved credentials for HTTP authentication.
+     * Clears any saved credentials for HTTP authentication. This method only clears the username
+     * and password stored in WebViewDatabase instance. The username and password are not read from
+     * the {@link WebViewDatabase} during {@link WebViewClient#onReceivedHttpAuthRequest}. It is up
+     * to the app to do this or not.
+     * <p>
+     * The username and password used for http authentication might be cached in the network stack
+     * itself, and are not cleared when this method is called.  WebView does not provide a special
+     * mechanism to clear HTTP authentication for implementing client logout. The client logout
+     * mechanism should be implemented by the Web site designer (such as server sending a HTTP 401
+     * for invalidating credentials).
      *
      * @see WebView#getHttpAuthUsernamePassword
      * @see WebView#setHttpAuthUsernamePassword
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index e147ed6..e45e413 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -25,6 +25,8 @@
 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;
@@ -326,13 +328,6 @@
     }
 
     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() {
@@ -343,7 +338,13 @@
         };
 
         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
-        final Handler mHandler = new Handler();
+        final Handler mHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                IBinder token = (IBinder) msg.obj;
+                handleShow(token);
+            }
+        };
 
         int mGravity;
         int mX, mY;
@@ -379,9 +380,9 @@
          * schedule handleShow into the right thread
          */
         @Override
-        public void show() {
+        public void show(IBinder windowToken) {
             if (localLOGV) Log.v(TAG, "SHOW: " + this);
-            mHandler.post(mShow);
+            mHandler.obtainMessage(0, windowToken).sendToTarget();
         }
 
         /**
@@ -393,7 +394,7 @@
             mHandler.post(mHide);
         }
 
-        public void handleShow() {
+        public void handleShow(IBinder windowToken) {
             if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
                     + " mNextView=" + mNextView);
             if (mView != mNextView) {
@@ -422,8 +423,9 @@
                 mParams.verticalMargin = mVerticalMargin;
                 mParams.horizontalMargin = mHorizontalMargin;
                 mParams.packageName = packageName;
-                mParams.removeTimeoutMilliseconds = mDuration ==
+                mParams.hideTimeoutMilliseconds = 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/fd_utils-inl.h b/core/jni/fd_utils-inl.h
index 2b36c9f..7cfb4f3 100644
--- a/core/jni/fd_utils-inl.h
+++ b/core/jni/fd_utils-inl.h
@@ -48,7 +48,6 @@
 // fork, and all operations on it will fail.
 static const char* kPathWhitelist[] = {
   "/dev/null",
-  "/dev/pmsg0",
   "/dev/socket/zygote",
   "/dev/socket/zygote_secondary",
   "/system/etc/event-log-tags",
diff --git a/core/res/res/anim/dock_bottom_exit_keyguard.xml b/core/res/res/anim/dock_bottom_exit_keyguard.xml
new file mode 100644
index 0000000..4de3ce5
--- /dev/null
+++ b/core/res/res/anim/dock_bottom_exit_keyguard.xml
@@ -0,0 +1,22 @@
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!-- Animation for when a dock window at the bottom of the screen is exiting while on Keyguard -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:interpolator="@android:interpolator/fast_out_linear_in">
+    <translate android:fromYDelta="0" android:toYDelta="100%"
+        android:duration="200"/>
+</set>
\ No newline at end of file
diff --git a/core/res/res/drawable-hdpi/vpn_connected.png b/core/res/res/drawable-hdpi/vpn_connected.png
index c3547e8..e05e76f 100644
--- a/core/res/res/drawable-hdpi/vpn_connected.png
+++ b/core/res/res/drawable-hdpi/vpn_connected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/vpn_disconnected.png b/core/res/res/drawable-hdpi/vpn_disconnected.png
index 10a9065..3508984 100644
--- a/core/res/res/drawable-hdpi/vpn_disconnected.png
+++ b/core/res/res/drawable-hdpi/vpn_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/vpn_connected.png b/core/res/res/drawable-mdpi/vpn_connected.png
index 7e167f8..f7ac2a1 100644
--- a/core/res/res/drawable-mdpi/vpn_connected.png
+++ b/core/res/res/drawable-mdpi/vpn_connected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/vpn_disconnected.png b/core/res/res/drawable-mdpi/vpn_disconnected.png
index a08c42a..9db4199 100644
--- a/core/res/res/drawable-mdpi/vpn_disconnected.png
+++ b/core/res/res/drawable-mdpi/vpn_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/vpn_connected.xml b/core/res/res/drawable-nodpi/vpn_connected.xml
new file mode 100644
index 0000000..22a4a6cb4
--- /dev/null
+++ b/core/res/res/drawable-nodpi/vpn_connected.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M25.3,20c-1.65,-4.66 -6.08,-8 -11.3,-8 -6.63,0 -12,5.37 -12,12s5.37,12 12,12c5.22,0 9.65,-3.34 11.3,-8H34v8h8v-8h4v-8H25.3zM14,28c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
+</vector>
diff --git a/core/res/res/drawable-nodpi/vpn_disconnected.xml b/core/res/res/drawable-nodpi/vpn_disconnected.xml
new file mode 100644
index 0000000..22a4a6cb4
--- /dev/null
+++ b/core/res/res/drawable-nodpi/vpn_disconnected.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M25.3,20c-1.65,-4.66 -6.08,-8 -11.3,-8 -6.63,0 -12,5.37 -12,12s5.37,12 12,12c5.22,0 9.65,-3.34 11.3,-8H34v8h8v-8h4v-8H25.3zM14,28c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
+</vector>
diff --git a/core/res/res/drawable-xhdpi/vpn_connected.png b/core/res/res/drawable-xhdpi/vpn_connected.png
index 1f46be2..a8761c9 100644
--- a/core/res/res/drawable-xhdpi/vpn_connected.png
+++ b/core/res/res/drawable-xhdpi/vpn_connected.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/vpn_disconnected.png b/core/res/res/drawable-xhdpi/vpn_disconnected.png
index 847d3f5..7118918 100644
--- a/core/res/res/drawable-xhdpi/vpn_disconnected.png
+++ b/core/res/res/drawable-xhdpi/vpn_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/vpn_connected.png b/core/res/res/drawable-xxhdpi/vpn_connected.png
index ea4930c..16b1e4e 100644
--- a/core/res/res/drawable-xxhdpi/vpn_connected.png
+++ b/core/res/res/drawable-xxhdpi/vpn_connected.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/vpn_disconnected.png b/core/res/res/drawable-xxhdpi/vpn_disconnected.png
index 4cd0dd4..a025818 100644
--- a/core/res/res/drawable-xxhdpi/vpn_disconnected.png
+++ b/core/res/res/drawable-xxhdpi/vpn_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable/ic_check_circle_24px.xml b/core/res/res/drawable/ic_check_circle_24px.xml
index 066a8a7..e9af9e4 100644
--- a/core/res/res/drawable/ic_check_circle_24px.xml
+++ b/core/res/res/drawable/ic_check_circle_24px.xml
@@ -19,9 +19,6 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:pathData="M0 0h24v24H0z"
-        android:fillColor="#00000000"/>
-    <path
         android:fillColor="#FF000000"
         android:pathData="M12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zm-2.0,15.0l-5.0,-5.0 1.41,-1.41L10.0,14.17l7.59,-7.59L19.0,8.0l-9.0,9.0z"/>
 </vector>
diff --git a/core/res/res/drawable/ic_collapse_notification.xml b/core/res/res/drawable/ic_collapse_notification.xml
index 603c159..124e99e 100644
--- a/core/res/res/drawable/ic_collapse_notification.xml
+++ b/core/res/res/drawable/ic_collapse_notification.xml
@@ -22,7 +22,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M12.0,8.0l-6.0,6.0l1.4,1.4l4.6,-4.6l4.6,4.6L18.0,14.0L12.0,8.0z"/>
-    <path
-        android:pathData="M0,0h24v24H0V0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/core/res/res/drawable/ic_expand_more_48dp.xml b/core/res/res/drawable/ic_expand_more_48dp.xml
index 11323e3..5a71669 100644
--- a/core/res/res/drawable/ic_expand_more_48dp.xml
+++ b/core/res/res/drawable/ic_expand_more_48dp.xml
@@ -21,7 +21,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M33.17,17.17L24.0,26.34l-9.17,-9.17L12.0,20.0l12.0,12.0 12.0,-12.0z"/>
-    <path
-        android:pathData="M0 0h48v48H0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/core/res/res/drawable/ic_expand_notification.xml b/core/res/res/drawable/ic_expand_notification.xml
index db7d3eb..847e326 100644
--- a/core/res/res/drawable/ic_expand_notification.xml
+++ b/core/res/res/drawable/ic_expand_notification.xml
@@ -22,7 +22,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M16.6,8.6L12.0,13.2L7.4,8.6L6.0,10.0l6.0,6.0l6.0,-6.0L16.6,8.6z"/>
-    <path
-        android:pathData="M0,0h24v24H0V0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/core/res/res/drawable/ic_feedback.xml b/core/res/res/drawable/ic_feedback.xml
index b2d1cb8..365863d 100644
--- a/core/res/res/drawable/ic_feedback.xml
+++ b/core/res/res/drawable/ic_feedback.xml
@@ -19,9 +19,6 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:pathData="M0 0h24v24H0z"
-        android:fillColor="#00000000"/>
-    <path
         android:fillColor="#FF000000"
         android:pathData="M20.0,2.0L4.0,2.0c-1.1,0.0 -1.9,0.9 -1.99,2.0L2.0,22.0l4.0,-4.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L22.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,12.0l-2.0,0.0l0.0,-2.0l2.0,0.0l0.0,2.0zm0.0,-4.0l-2.0,0.0L11.0,6.0l2.0,0.0l0.0,4.0z"/>
 </vector>
diff --git a/core/res/res/drawable/ic_more_items.xml b/core/res/res/drawable/ic_more_items.xml
index 5fdcdce..0ec754c 100644
--- a/core/res/res/drawable/ic_more_items.xml
+++ b/core/res/res/drawable/ic_more_items.xml
@@ -24,6 +24,5 @@
         android:fillColor="#000000"
         android:pathData="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7
 7v2h14V7H7z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
+
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_schedule.xml b/core/res/res/drawable/ic_schedule.xml
index 899dc82..55d54b1 100644
--- a/core/res/res/drawable/ic_schedule.xml
+++ b/core/res/res/drawable/ic_schedule.xml
@@ -22,9 +22,6 @@
         android:fillColor="#FF000000"
         android:pathData="M11.99,2.0C6.47,2.0 2.0,6.48 2.0,12.0s4.47,10.0 9.99,10.0C17.52,22.0 22.0,17.52 22.0,12.0S17.52,2.0 11.99,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.58 -8.0,-8.0s3.58,-8.0 8.0,-8.0 8.0,3.58 8.0,8.0 -3.58,8.0 -8.0,8.0z"/>
     <path
-        android:pathData="M0 0h24v24H0z"
-        android:fillColor="#00000000"/>
-    <path
         android:fillColor="#FF000000"
         android:pathData="M12.5,7.0L11.0,7.0l0.0,6.0l5.25,3.1 0.75,-1.23 -4.5,-2.67z"/>
 </vector>
diff --git a/core/res/res/drawable/perm_group_calendar.xml b/core/res/res/drawable/perm_group_calendar.xml
index 4dc7b37..85a783e 100644
--- a/core/res/res/drawable/perm_group_calendar.xml
+++ b/core/res/res/drawable/perm_group_calendar.xml
@@ -24,6 +24,5 @@
         android:fillColor="#000000"
         android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99 .9 -1.99 2L3 19c0 1.1 .89 2 2
 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
+
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_camera.xml b/core/res/res/drawable/perm_group_camera.xml
index 741a40e..61903a5 100644
--- a/core/res/res/drawable/perm_group_camera.xml
+++ b/core/res/res/drawable/perm_group_camera.xml
@@ -28,6 +28,4 @@
         android:pathData="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1 0 2-.9
 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5
 5-2.24 5-5 5z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_contacts.xml b/core/res/res/drawable/perm_group_contacts.xml
index d698fd1..8f9dc3e 100644
--- a/core/res/res/drawable/perm_group_contacts.xml
+++ b/core/res/res/drawable/perm_group_contacts.xml
@@ -21,8 +21,6 @@
     android:viewportHeight="24">
 
     <path
-        android:pathData="M0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0z" />
-    <path
         android:fillColor="#000000"
         android:pathData="M20 0H4v2h16V0zM4 24h16v-2H4v2zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1
 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 2.75c1.24 0 2.25 1.01 2.25 2.25s-1.01 2.25-2.25
diff --git a/core/res/res/drawable/perm_group_location.xml b/core/res/res/drawable/perm_group_location.xml
index fbc6066..cc1ec90 100644
--- a/core/res/res/drawable/perm_group_location.xml
+++ b/core/res/res/drawable/perm_group_location.xml
@@ -24,6 +24,4 @@
         android:fillColor="#000000"
         android:pathData="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0
 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_microphone.xml b/core/res/res/drawable/perm_group_microphone.xml
index c565d20..d494e67 100644
--- a/core/res/res/drawable/perm_group_microphone.xml
+++ b/core/res/res/drawable/perm_group_microphone.xml
@@ -25,6 +25,4 @@
         android:pathData="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3
 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6
 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_phone_calls.xml b/core/res/res/drawable/perm_group_phone_calls.xml
index a647894..324d864 100644
--- a/core/res/res/drawable/perm_group_phone_calls.xml
+++ b/core/res/res/drawable/perm_group_phone_calls.xml
@@ -19,9 +19,6 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
-
-    <path
-        android:pathData="M0 0h24v24H0z" />
     <path
         android:fillColor="#000000"
         android:pathData="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27 .67 -.36 1.02-.24 1.12
diff --git a/core/res/res/drawable/perm_group_sms.xml b/core/res/res/drawable/perm_group_sms.xml
index 9b32c601..47bca19e 100644
--- a/core/res/res/drawable/perm_group_sms.xml
+++ b/core/res/res/drawable/perm_group_sms.xml
@@ -24,6 +24,4 @@
         android:fillColor="#000000"
         android:pathData="M20 2H4c-1.1 0-1.99 .9 -1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM9
 11H7V9h2v2zm4 0h-2V9h2v2zm4 0h-2V9h2v2z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_storage.xml b/core/res/res/drawable/perm_group_storage.xml
index 477270d..1ff1693 100644
--- a/core/res/res/drawable/perm_group_storage.xml
+++ b/core/res/res/drawable/perm_group_storage.xml
@@ -24,6 +24,4 @@
         android:fillColor="#000000"
         android:pathData="M10 4H4c-1.1 0-1.99 .9 -1.99 2L2 18c0 1.1 .9 2 2 2h16c1.1 0 2-.9
 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
\ No newline at end of file
diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
index f2933b7..d638b89 100644
--- a/core/res/res/values-mcc302-mnc220/config.xml
+++ b/core/res/res/values-mcc302-mnc220/config.xml
@@ -44,11 +44,11 @@
 
     <!-- Values for GPS configuration (Telus) -->
     <string-array translatable="false" name="config_gpsParameters">
-        <item>SUPL_HOST=supl.google.com</item>
+        <item>SUPL_HOST=supl.telusmobility.com</item>
         <item>SUPL_PORT=7275</item>
-        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra2.bin</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
         <item>NTP_SERVER=north-america.pool.ntp.org</item>
         <item>SUPL_MODE=1</item>
         <item>SUPL_VER=0x20000</item>
@@ -57,8 +57,8 @@
         <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
         <item>ERR_ESTIMATE=0</item>
         <item>INTERMEDIATE_POS=0</item>
-        <item>GPS_LOCK=3</item>
-        <item>SUPL_ES=1</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</item>
     </string-array>
 
 </resources>
diff --git a/core/res/res/values-mcc302-mnc221/config.xml b/core/res/res/values-mcc302-mnc221/config.xml
index 28b5545..1444250 100644
--- a/core/res/res/values-mcc302-mnc221/config.xml
+++ b/core/res/res/values-mcc302-mnc221/config.xml
@@ -34,11 +34,11 @@
 
     <!-- Values for GPS configuration (Telus) -->
     <string-array translatable="false" name="config_gpsParameters">
-        <item>SUPL_HOST=supl.google.com</item>
+        <item>SUPL_HOST=supl.telusmobility.com</item>
         <item>SUPL_PORT=7275</item>
-        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra2.bin</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
         <item>NTP_SERVER=north-america.pool.ntp.org</item>
         <item>SUPL_MODE=1</item>
         <item>SUPL_VER=0x20000</item>
@@ -47,8 +47,8 @@
         <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
         <item>ERR_ESTIMATE=0</item>
         <item>INTERMEDIATE_POS=0</item>
-        <item>GPS_LOCK=3</item>
-        <item>SUPL_ES=1</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</item>
     </string-array>
 
 </resources>
diff --git a/core/res/res/values-mcc302-mnc370/config.xml b/core/res/res/values-mcc302-mnc370/config.xml
index ec402fb..05265c7 100644
--- a/core/res/res/values-mcc302-mnc370/config.xml
+++ b/core/res/res/values-mcc302-mnc370/config.xml
@@ -47,9 +47,9 @@
     <string-array translatable="false" name="config_gpsParameters">
         <item>SUPL_HOST=supl.google.com</item>
         <item>SUPL_PORT=7275</item>
-        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra2.bin</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
         <item>NTP_SERVER=north-america.pool.ntp.org</item>
         <item>SUPL_MODE=1</item>
         <item>SUPL_VER=0x20000</item>
@@ -58,8 +58,8 @@
         <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
         <item>ERR_ESTIMATE=0</item>
         <item>INTERMEDIATE_POS=0</item>
-        <item>GPS_LOCK=3</item>
-        <item>SUPL_ES=1</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</item>
     </string-array>
 
 </resources>
diff --git a/core/res/res/values-mcc302-mnc610/config.xml b/core/res/res/values-mcc302-mnc610/config.xml
index 73604a3..0af2c39 100644
--- a/core/res/res/values-mcc302-mnc610/config.xml
+++ b/core/res/res/values-mcc302-mnc610/config.xml
@@ -31,9 +31,9 @@
     <string-array translatable="false" name="config_gpsParameters">
         <item>SUPL_HOST=supl.google.com</item>
         <item>SUPL_PORT=7275</item>
-        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra2.bin</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
         <item>NTP_SERVER=north-america.pool.ntp.org</item>
         <item>SUPL_MODE=1</item>
         <item>SUPL_VER=0x20000</item>
@@ -42,7 +42,7 @@
         <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
         <item>ERR_ESTIMATE=0</item>
         <item>INTERMEDIATE_POS=0</item>
-        <item>GPS_LOCK=3</item>
-        <item>SUPL_ES=1</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</item>
     </string-array>
 </resources>
diff --git a/core/res/res/values-mcc302-mnc640/config.xml b/core/res/res/values-mcc302-mnc640/config.xml
index 8597c65..e005bc0 100644
--- a/core/res/res/values-mcc302-mnc640/config.xml
+++ b/core/res/res/values-mcc302-mnc640/config.xml
@@ -27,9 +27,9 @@
     <string-array translatable="false" name="config_gpsParameters">
         <item>SUPL_HOST=supl.google.com</item>
         <item>SUPL_PORT=7275</item>
-        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra2.bin</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
         <item>NTP_SERVER=north-america.pool.ntp.org</item>
         <item>SUPL_MODE=1</item>
         <item>SUPL_VER=0x20000</item>
@@ -38,7 +38,7 @@
         <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
         <item>ERR_ESTIMATE=0</item>
         <item>INTERMEDIATE_POS=0</item>
-        <item>GPS_LOCK=3</item>
-        <item>SUPL_ES=1</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</item>
     </string-array>
 </resources>
diff --git a/core/res/res/values-mcc302-mnc720/config.xml b/core/res/res/values-mcc302-mnc720/config.xml
index 8b4ed30..7a3540a 100644
--- a/core/res/res/values-mcc302-mnc720/config.xml
+++ b/core/res/res/values-mcc302-mnc720/config.xml
@@ -49,9 +49,9 @@
     <string-array translatable="false" name="config_gpsParameters">
         <item>SUPL_HOST=supl.google.com</item>
         <item>SUPL_PORT=7275</item>
-        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra2.bin</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
         <item>NTP_SERVER=north-america.pool.ntp.org</item>
         <item>SUPL_MODE=1</item>
         <item>SUPL_VER=0x20000</item>
@@ -60,8 +60,8 @@
         <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
         <item>ERR_ESTIMATE=0</item>
         <item>INTERMEDIATE_POS=0</item>
-        <item>GPS_LOCK=3</item>
-        <item>SUPL_ES=1</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</item>
     </string-array>
 
 </resources>
diff --git a/core/res/res/values-watch/colors_material.xml b/core/res/res/values-watch/colors_material.xml
index 45eb981..54eece4 100644
--- a/core/res/res/values-watch/colors_material.xml
+++ b/core/res/res/values-watch/colors_material.xml
@@ -22,5 +22,5 @@
 
     <color name="primary_material_dark">#4D4D4D</color>
 
-    <color name="button_material_dark">#ff999999</color>
+    <color name="button_material_dark">#ff919699</color>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8c7cab2..62b9435 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3334,10 +3334,12 @@
     <string name="vpn_lockdown_connecting">Always-on VPN connecting\u2026</string>
     <!-- Notification title when connected to lockdown VPN. -->
     <string name="vpn_lockdown_connected">Always-on VPN connected</string>
+    <!-- Notification title when not connected to lockdown VPN. -->
+    <string name="vpn_lockdown_disconnected">Always-on VPN disconnected</string>
     <!-- Notification title when error connecting to lockdown VPN. -->
     <string name="vpn_lockdown_error">Always-on VPN error</string>
     <!-- Notification body that indicates user can touch to configure lockdown VPN connection. -->
-    <string name="vpn_lockdown_config">Tap to configure</string>
+    <string name="vpn_lockdown_config">Tap to set up</string>
 
     <!-- Localized strings for WebView -->
     <!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7a0e8ca..96ab3162 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1462,6 +1462,7 @@
   <java-symbol type="anim" name="dock_top_exit" />
   <java-symbol type="anim" name="dock_bottom_enter" />
   <java-symbol type="anim" name="dock_bottom_exit" />
+  <java-symbol type="anim" name="dock_bottom_exit_keyguard" />
   <java-symbol type="anim" name="dock_left_enter" />
   <java-symbol type="anim" name="dock_left_exit" />
   <java-symbol type="anim" name="dock_right_enter" />
@@ -1877,6 +1878,7 @@
   <java-symbol type="string" name="vpn_title_long" />
   <java-symbol type="string" name="vpn_lockdown_connecting" />
   <java-symbol type="string" name="vpn_lockdown_connected" />
+  <java-symbol type="string" name="vpn_lockdown_disconnected" />
   <java-symbol type="string" name="vpn_lockdown_error" />
   <java-symbol type="string" name="vpn_lockdown_config" />
   <java-symbol type="string" name="wallpaper_binding_label" />
diff --git a/docs/html-intl/intl/es/about/versions/nougat/index.jd b/docs/html-intl/intl/es/about/versions/nougat/index.jd
index b30cc88..59afd81 100644
--- a/docs/html-intl/intl/es/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/es/about/versions/nougat/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
@@ -54,7 +44,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -76,26 +66,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Informar un problema
-      </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Consulta las notas de la versión
-      </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Únete a la comunidad de desarrolladores
-        </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
   <h2 class="norule">Lo último</h2>
   <div class="resource-widget resource-flow-layout col-16"
diff --git a/docs/html-intl/intl/es/index.jd b/docs/html-intl/intl/es/index.jd
index e0d80c1..1ecf47c 100644
--- a/docs/html-intl/intl/es/index.jd
+++ b/docs/html-intl/intl/es/index.jd
@@ -5,16 +5,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
   <div class="wrap" style="max-width:1000px;margin-top:0">
     <div class="col-7of16 col-push-8of16">
@@ -44,7 +34,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -72,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/in/about/versions/nougat/index.jd b/docs/html-intl/intl/in/about/versions/nougat/index.jd
index 5234f91..212870a 100644
--- a/docs/html-intl/intl/in/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/in/about/versions/nougat/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
@@ -55,7 +45,7 @@
 </section>
 
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -77,26 +67,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Laporkan masalah
-          </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Lihat catatan rilis
-          </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Bergabunglah dengan komunitas pengembang
-          </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
   <h2 class="norule">Terbaru</h2>
   <div class="resource-widget resource-flow-layout col-16"
diff --git a/docs/html-intl/intl/ja/about/versions/nougat/index.jd b/docs/html-intl/intl/ja/about/versions/nougat/index.jd
index 5881cf6..7c5fe5d 100644
--- a/docs/html-intl/intl/ja/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/ja/about/versions/nougat/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
@@ -55,7 +45,7 @@
 </section>
 
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -77,26 +67,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        問題の報告</a>
-</div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        リリースノートの確認</a>
-</div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        開発者コミュニティに参加</a>
-</div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
   <h2 class="norule">新着</h2>
   <div class="resource-widget resource-flow-layout col-16"
diff --git a/docs/html-intl/intl/ja/index.jd b/docs/html-intl/intl/ja/index.jd
index ba73c41..3220f19 100644
--- a/docs/html-intl/intl/ja/index.jd
+++ b/docs/html-intl/intl/ja/index.jd
@@ -5,16 +5,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
   <div class="wrap" style="max-width:1000px;margin-top:0">
     <div class="col-7of16 col-push-8of16">
@@ -44,7 +34,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -72,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/ko/about/versions/nougat/index.jd b/docs/html-intl/intl/ko/about/versions/nougat/index.jd
index 6ed065b..20561a4 100644
--- a/docs/html-intl/intl/ko/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/ko/about/versions/nougat/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
@@ -54,7 +44,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -76,26 +66,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        문제 보고
-      </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        릴리스 노트 보기
-        </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        개발자 커뮤니티 가입
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
   <h2 class="norule">최신</h2>
   <div class="resource-widget resource-flow-layout col-16"
diff --git a/docs/html-intl/intl/ko/index.jd b/docs/html-intl/intl/ko/index.jd
index e102411..b459df7 100644
--- a/docs/html-intl/intl/ko/index.jd
+++ b/docs/html-intl/intl/ko/index.jd
@@ -5,16 +5,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
   <div class="wrap" style="max-width:1000px;margin-top:0">
     <div class="col-7of16 col-push-8of16">
@@ -44,7 +34,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -72,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd b/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
index c7aee2a..ff44f6a 100644
--- a/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
@@ -54,7 +44,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
diff --git a/docs/html-intl/intl/pt-br/index.jd b/docs/html-intl/intl/pt-br/index.jd
index 3c8f75d..b15ecc8 100644
--- a/docs/html-intl/intl/pt-br/index.jd
+++ b/docs/html-intl/intl/pt-br/index.jd
@@ -5,16 +5,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
   <div class="wrap" style="max-width:1000px;margin-top:0">
     <div class="col-7of16 col-push-8of16">
@@ -44,7 +34,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -72,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/ru/about/versions/nougat/index.jd b/docs/html-intl/intl/ru/about/versions/nougat/index.jd
index 1103166..0365061 100644
--- a/docs/html-intl/intl/ru/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/ru/about/versions/nougat/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
@@ -54,7 +44,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -76,26 +66,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Сообщить о проблеме
-        </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        См. примечания к выпуску
-        </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Вступить в сообщество разработчиков
-        </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
   <h2 class="norule">Latest</h2>
   <div class="resource-widget resource-flow-layout col-16"
diff --git a/docs/html-intl/intl/ru/index.jd b/docs/html-intl/intl/ru/index.jd
index b3f3cc2..83a506e 100644
--- a/docs/html-intl/intl/ru/index.jd
+++ b/docs/html-intl/intl/ru/index.jd
@@ -5,16 +5,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
   <div class="wrap" style="max-width:1000px;margin-top:0">
     <div class="col-7of16 col-push-8of16">
@@ -44,7 +34,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -72,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/vi/about/versions/nougat/index.jd b/docs/html-intl/intl/vi/about/versions/nougat/index.jd
index 58b4b5f..2d57fa6 100644
--- a/docs/html-intl/intl/vi/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/vi/about/versions/nougat/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
@@ -55,7 +45,7 @@
 </section>
 
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -77,26 +67,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Báo cáo vấn đề
-      </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Xem ghi chú phát hành
-      </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Tham gia cộng đồng nhà phát triển
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
   <h2 class="norule">Latest</h2>
   <div class="resource-widget resource-flow-layout col-16"
diff --git a/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd b/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
index c1eb423..5619de8 100644
--- a/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
@@ -55,7 +45,7 @@
 </section>
 
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -77,26 +67,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        报告问题
-      </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        查阅版本说明
-      </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        加入开发者社区</a>
-</div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
   <h2 class="norule">最新</h2>
   <div class="resource-widget resource-flow-layout col-16"
diff --git a/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd b/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
index 1c82161..cc1234d 100644
--- a/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
+++ b/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
@@ -35,7 +35,7 @@
   vertical-align: middle;
   margin: 0 5px 0 0;
 }
-#jd-content div.button-row img {
+#body-content div.button-row img {
   margin: 0;
   vertical-align: middle;
 }
diff --git a/docs/html-intl/intl/zh-cn/index.jd b/docs/html-intl/intl/zh-cn/index.jd
index 8872d16..c1a5d6f 100644
--- a/docs/html-intl/intl/zh-cn/index.jd
+++ b/docs/html-intl/intl/zh-cn/index.jd
@@ -5,16 +5,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
   <div class="wrap" style="max-width:1000px;margin-top:0">
     <div class="col-7of16 col-push-8of16">
@@ -44,7 +34,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -72,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd b/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
index d4db467..ae9e164 100644
--- a/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
@@ -55,7 +45,7 @@
 </section>
 
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -77,26 +67,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        回報問題</a>
-</div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        查看版本資訊</a>
-</div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        加入開發人員社群</a>
-</div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
   <h2 class="norule">Latest</h2>
   <div class="resource-widget resource-flow-layout col-16"
diff --git a/docs/html-intl/intl/zh-tw/index.jd b/docs/html-intl/intl/zh-tw/index.jd
index 540801a..022df77 100644
--- a/docs/html-intl/intl/zh-tw/index.jd
+++ b/docs/html-intl/intl/zh-tw/index.jd
@@ -5,16 +5,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
   <div class="wrap" style="max-width:1000px;margin-top:0">
     <div class="col-7of16 col-push-8of16">
@@ -44,7 +34,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -72,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html/about/versions/android-1.5.jd b/docs/html/about/versions/android-1.5.jd
index 45a27ee..6db5472 100644
--- a/docs/html/about/versions/android-1.5.jd
+++ b/docs/html/about/versions/android-1.5.jd
@@ -101,7 +101,7 @@
 .toggleable.closed .toggleme {
   display:none;
 }
-#jd-content .toggle-img {
+#body-content .toggle-img {
   margin:0;
 }
 </style>
diff --git a/docs/html/about/versions/android-1.6-highlights.jd b/docs/html/about/versions/android-1.6-highlights.jd
index 9179579..f594449 100644
--- a/docs/html/about/versions/android-1.6-highlights.jd
+++ b/docs/html/about/versions/android-1.6-highlights.jd
@@ -6,8 +6,8 @@
 
 
 <style type="text/css">
-#jd-content div.screenshot,
-#jd-content div.video {
+#body-content div.screenshot,
+#body-content div.video {
   float:right;
   clear:right;
   padding:15px 70px;
@@ -15,11 +15,11 @@
   font-weight:bold;
   line-height:1.7em;
 }
-#jd-content div.video {
+#body-content div.video {
   padding-top:0;
   margin-top:-15px;
 }
-#jd-content div.screenshot img {
+#body-content div.screenshot img {
   margin:0;
 }
 </style>
diff --git a/docs/html/about/versions/android-1.6.jd b/docs/html/about/versions/android-1.6.jd
index 970c343..a84c225 100755
--- a/docs/html/about/versions/android-1.6.jd
+++ b/docs/html/about/versions/android-1.6.jd
@@ -103,7 +103,7 @@
 .toggleable.closed .toggleme {
   display:none;
 }
-#jd-content .toggle-img {
+#body-content .toggle-img {
   margin:0;
 }
 </style>
diff --git a/docs/html/about/versions/android-2.0-highlights.jd b/docs/html/about/versions/android-2.0-highlights.jd
index 3f7e1c8..017b16f 100644
--- a/docs/html/about/versions/android-2.0-highlights.jd
+++ b/docs/html/about/versions/android-2.0-highlights.jd
@@ -6,8 +6,8 @@
 
 
 <style type="text/css">
-#jd-content div.screenshot,
-#jd-content div.video {
+#body-content div.screenshot,
+#body-content div.video {
   float:right;
   clear:right;
   padding:15px 60px;
@@ -15,15 +15,15 @@
   font-weight:bold;
   line-height:1.7em;
 }
-#jd-content div.video {
+#body-content div.video {
   padding-top:0;
   margin-top:-15px;
 }
-#jd-content div.screenshot.second {
+#body-content div.screenshot.second {
   clear:none;
   padding:15px 0 15px 60px;
 }
-#jd-content div.screenshot img {
+#body-content div.screenshot img {
   margin:0;
   border:1px solid #ccc;
 }
diff --git a/docs/html/about/versions/android-2.0.1.jd b/docs/html/about/versions/android-2.0.1.jd
index b0f4db6..21bfa65 100644
--- a/docs/html/about/versions/android-2.0.1.jd
+++ b/docs/html/about/versions/android-2.0.1.jd
@@ -99,7 +99,7 @@
 .toggleable.closed .toggleme {
   display:none;
 }
-#jd-content .toggle-img {
+#body-content .toggle-img {
   margin:0;
 }
 </style>
diff --git a/docs/html/about/versions/android-2.0.jd b/docs/html/about/versions/android-2.0.jd
index 0323686..8029633 100644
--- a/docs/html/about/versions/android-2.0.jd
+++ b/docs/html/about/versions/android-2.0.jd
@@ -92,7 +92,7 @@
 .toggleable.closed .toggleme {
   display:none;
 }
-#jd-content .toggle-img {
+#body-content .toggle-img {
   margin:0;
 }
 </style>
diff --git a/docs/html/about/versions/android-2.2-highlights.jd b/docs/html/about/versions/android-2.2-highlights.jd
index afbf26b..37a7a82 100644
--- a/docs/html/about/versions/android-2.2-highlights.jd
+++ b/docs/html/about/versions/android-2.2-highlights.jd
@@ -5,32 +5,32 @@
 
 
 <style type="text/css">
-#jd-content {
+#body-content {
   max-width:800px;
 }
-#jd-content div.screenshot {
+#body-content div.screenshot {
   float:left;
   clear:left;
   padding:15px 30px 15px 0;
 }
-#jd-content div.video {
+#body-content div.video {
   float:right;
   padding:0 60px 40px;
   margin-top:-15px;
 }
-#jd-content table.columns {
+#body-content table.columns {
   margin:0 0 1em 0;
 }
-#jd-content table.columns td {
+#body-content table.columns td {
   padding:0;
 }
-#jd-content table.columns td+td {
+#body-content table.columns td+td {
   padding:0 2em;
 }
-#jd-content table.columns td img {
+#body-content table.columns td img {
   margin:0;
 }
-#jd-content table.columns td+td>*:first-child {
+#body-content table.columns td+td>*:first-child {
   margin-top:-2em;
 }
 .green {
diff --git a/docs/html/about/versions/android-2.3-highlights.jd b/docs/html/about/versions/android-2.3-highlights.jd
index 582bce9..013ec7f 100644
--- a/docs/html/about/versions/android-2.3-highlights.jd
+++ b/docs/html/about/versions/android-2.3-highlights.jd
@@ -4,31 +4,31 @@
 
 
 <style type="text/css">
-#jd-content {
+#body-content {
   max-width:1200px;
 }
-#jd-content div.screenshot {
+#body-content div.screenshot {
   float:left;
   clear:left;
   padding:15px 30px 15px 0;
 }
-#jd-content div.video {
+#body-content div.video {
   float:right;
   padding:0 0 0 40px;
 }
-#jd-content table.columns {
+#body-content table.columns {
   margin:0 0 1em 0;
 }
-#jd-content table.columns td {
+#body-content table.columns td {
   padding:0;
 }
-#jd-content table.columns td+td {
+#body-content table.columns td+td {
   padding:0 2em;
 }
-#jd-content table.columns td img {
+#body-content table.columns td img {
   margin:0;
 }
-#jd-content table.columns td+td>*:first-child {
+#body-content table.columns td+td>*:first-child {
   margin-top:-2em;
 }
 .green {
diff --git a/docs/html/about/versions/android-3.0-highlights.jd b/docs/html/about/versions/android-3.0-highlights.jd
index e9d2b39..50d4667 100644
--- a/docs/html/about/versions/android-3.0-highlights.jd
+++ b/docs/html/about/versions/android-3.0-highlights.jd
@@ -4,31 +4,31 @@
 
 
 <style type="text/css">
-#jd-content {
+#body-content {
   max-width:1200px;
 }
-#jd-content div.screenshot {
+#body-content div.screenshot {
   float:left;
   clear:left;
   padding:15px 30px 15px 0;
 }
-#jd-content div.video {
+#body-content div.video {
   float:right;
   padding:0 60px 40px;
 }
-#jd-content table.columns {
+#body-content table.columns {
   margin:0 0 1em 0;
 }
-#jd-content table.columns td {
+#body-content table.columns td {
   padding:0;
 }
-#jd-content table.columns td+td {
+#body-content table.columns td+td {
   padding:0 2em;
 }
-#jd-content table.columns td img {
+#body-content table.columns td img {
   margin:0;
 }
-#jd-content table.columns td+td>*:first-child {
+#body-content table.columns td+td>*:first-child {
   margin-top:-2em;
 }
 .green {
diff --git a/docs/html/about/versions/android-3.1-highlights.jd b/docs/html/about/versions/android-3.1-highlights.jd
index 2a70698..22df372 100644
--- a/docs/html/about/versions/android-3.1-highlights.jd
+++ b/docs/html/about/versions/android-3.1-highlights.jd
@@ -4,31 +4,31 @@
 
 
 <style type="text/css">
-#jd-content {
+#body-content {
   max-width:1200px;
 }
-#jd-content div.screenshot {
+#body-content div.screenshot {
   float:left;
   clear:left;
   padding:15px 30px 15px 0;
 }
-#jd-content div.video {
+#body-content div.video {
   float:right;
   padding:0 60px 40px;
 }
-#jd-content table.columns {
+#body-content table.columns {
   margin:0 0 1em 0;
 }
-#jd-content table.columns td {
+#body-content table.columns td {
   padding:0;
 }
-#jd-content table.columns td+td {
+#body-content table.columns td+td {
   padding:0 2em;
 }
-#jd-content table.columns td img {
+#body-content table.columns td img {
   margin:0;
 }
-#jd-content table.columns td+td>*:first-child {
+#body-content table.columns td+td>*:first-child {
   margin-top:-2em;
 }
 .green {
diff --git a/docs/html/about/versions/android-4.0-highlights.jd b/docs/html/about/versions/android-4.0-highlights.jd
index c980af6..57eb2a3 100755
--- a/docs/html/about/versions/android-4.0-highlights.jd
+++ b/docs/html/about/versions/android-4.0-highlights.jd
@@ -4,31 +4,31 @@
 
 
 <style type="text/css">
-#jd-content {
+#body-content {
   max-width:1024px;
 }
-#jd-content div.screenshot {
+#body-content div.screenshot {
   float:left;
   clear:left;
   padding:15px 30px 15px 0;
 }
-#jd-content div.video {
+#body-content div.video {
   float:right;
   padding:0 0 40px 60px;
 }
-#jd-content table.columns {
+#body-content table.columns {
   margin:0 0 1em 0;
 }
-#jd-content table.columns td {
+#body-content table.columns td {
   padding:0;
 }
-#jd-content table.columns td+td {
+#body-content table.columns td+td {
   padding:0 2em;
 }
-#jd-content table.columns td img {
+#body-content table.columns td img {
   margin:0;
 }
-#jd-content table.columns td+td>*:first-child {
+#body-content table.columns td+td>*:first-child {
   margin-top:-2em;
 }
 .green {
diff --git a/docs/html/about/versions/nougat/index.jd b/docs/html/about/versions/nougat/index.jd
index 30a3576..8661d77 100644
--- a/docs/html/about/versions/nougat/index.jd
+++ b/docs/html/about/versions/nougat/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
   <a href="{@docRoot}about/versions/nougat/android-7.0.html">
@@ -54,8 +44,7 @@
   </div>
 </section>
 
-
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -77,26 +66,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Report an issue
-      </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        See release notes
-      </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Join dev community
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
   <h2 class="norule">Latest</h2>
   <div class="resource-widget resource-flow-layout col-16"
diff --git a/docs/html/auto/index.jd b/docs/html/auto/index.jd
index e6fde38..3ebd87d 100644
--- a/docs/html/auto/index.jd
+++ b/docs/html/auto/index.jd
@@ -10,7 +10,7 @@
 
 <style>
 .fullpage>#footer,
-#jd-content>.content-footer.wrap {
+#body-content>.content-footer.wrap {
   display:none;
 }
 .img-logo {
diff --git a/docs/html/distribute/essentials/quality/wear.jd b/docs/html/distribute/essentials/quality/wear.jd
index 34c6cc5..be48491 100644
--- a/docs/html/distribute/essentials/quality/wear.jd
+++ b/docs/html/distribute/essentials/quality/wear.jd
@@ -42,6 +42,13 @@
   understand the basic implementation requirements for a Wear app.
 </p>
 
+<p>
+  This document helps you assess basic aspects of quality in your Wear app through a
+  compact set of functional and user interface quality criteria.
+   Make sure to check out the <a href="https://developer.android.com/wear/preview/index.html">Wear 2.0 preview</a>
+  documentation to get ready for the next version of Android Wear.
+</p>
+
 <p class="caution">
   <strong>Important:</strong> To ensure a great user experience, apps for wearables must meet
   specific requirements for usability. Only apps that meet the following quality criteria will
@@ -50,8 +57,8 @@
 </p>
 
 <p class="note">
- <strong>Note:</strong> For information about how to publish your Wear apps in Google Play, see <a
- href="{@docRoot}distribute/googleplay/wear.html">Distributing to Android Wear</a>.
+  <strong>Note:</strong> For information about how to publish your Wear apps in Google Play, see <a
+  href="{@docRoot}distribute/googleplay/wear.html">Distributing to Android Wear</a>.
 </p>
 
 <div class="headerLine">
@@ -67,6 +74,19 @@
   functional behavior.
 </p>
 
+<p class="caution">
+  <strong>Important:</strong> To learn about how Wear 2.0 platform changes may affect
+   your apps, see the <a href="https://developer.android.com/wear/preview/index.html">Wear 2.0 preview</a>
+   documentation.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> The symbol &#10008; is used in the table below to indicate
+  quality criteria that are not required for the corresponding Wear version.
+</p>
+
+<p class="table-caption"><strong>Table 1</strong>. Functional criteria.
+</p>
 
 <table>
 <tr>
@@ -79,6 +99,12 @@
   <th>
     Description
   </th>
+  <th>
+    Wear 1.0
+  </th>
+  <th>
+    Wear 2.0
+  </th>
 </tr>
 
 <tr>
@@ -96,6 +122,12 @@
       (<a href="{@docRoot}training/building-wearables.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -107,6 +139,12 @@
       App has Wear functionality that is visible to the user.
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -118,6 +156,12 @@
       Wear functionality works as expected or as described in the app's Google Play Store listing.
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -135,6 +179,12 @@
       (<a href="{@docRoot}training/wearables/apps/packaging.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -152,6 +202,12 @@
       (<a href="{@docRoot}training/wearables/notifications/index.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -164,6 +220,12 @@
       (<a href="{@docRoot}training/wearables/notifications/voice-input.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -176,6 +238,12 @@
       (<a href="{@docRoot}training/wearables/notifications/stacks.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -193,6 +261,12 @@
       (<a href="{@docRoot}training/wearables/ui/exit.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -206,6 +280,12 @@
       (<a href="{@docRoot}training/wearables/ui/exit.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -222,6 +302,12 @@
       (<a href="{@docRoot}training/wearables/watch-faces/index.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 </table>
@@ -245,8 +331,15 @@
 <p>
   These criteria ensure that your app follows critical design and interaction patterns to provide a
   consistent, intuitive, and enjoyable user experience on wearables.
+
+</p>
+<p clase="note">
+  <strong>Note:</strong> The symbol &#10008; is used in the table below to indicate
+  quality criteria that are not required for the corresponding Wear version.
 </p>
 
+<p class="table-caption"><strong>Table 2</strong>. Visual criteria.
+</p>
 <table>
 
 <tr>
@@ -259,6 +352,12 @@
   <th>
     Description
   </th>
+  <th>
+    Wear 1.0
+  </th>
+  <th>
+    Wear 2.0
+  </th>
 </tr>
 
 <tr>
@@ -277,6 +376,12 @@
       (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -292,6 +397,13 @@
       (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
+
 </tr>
 
 <tr>
@@ -304,6 +416,12 @@
       (<a href="{@docRoot}design/wear/style.html#Typography">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -320,6 +438,12 @@
       (<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -336,6 +460,12 @@
       (<a href="{@docRoot}design/wear/patterns.html#Countdown">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -350,6 +480,12 @@
       (<a href="{@docRoot}design/wear/style.html#Assets">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -363,6 +499,12 @@
       (<a href="{@docRoot}training/wearables/notifications/creating.html#ActionButtons">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -375,6 +517,12 @@
       (<a href="{@docRoot}design/wear/style.html#Branding">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -387,6 +535,12 @@
       (<a href="{@docRoot}training/wearables/notifications/creating.html#AddWearableFeatures">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -403,6 +557,12 @@
       (<a href="https://support.google.com/googleplay/android-developer/answer/1078870?hl=en">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 
diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
index 424983d..3d75758 100644
--- a/docs/html/distribute/index.jd
+++ b/docs/html/distribute/index.jd
@@ -9,16 +9,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <div class="dac-hero-carousel" data-carousel-query="collection:distribute/landing/carousel">
 </div>
 
@@ -28,18 +18,7 @@
   </a>
 </div>
 
-<section id="useOldTemplates" style="display:none" class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
-  <h2 class="norule">Latest</h2>
-  <div class="resource-widget resource-flow-layout col-16"
-      data-query="type:youtube+tag:googleplay+tag:developerstory+tag:featured, type:blog+tag:googleplay+tag:distribute+tag:featured"
-      data-sortOrder="-timestamp"
-      data-cardSizes="6x6"
-      data-maxResults="3"
-      data-items-per-page="6"
-      data-initial-results="3"></div>
-</div></section>
-
-<section id="useUpdatedTemplates" style="display:none" class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
+<section class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
   <h2 class="norule">Latest</h2>
 
   <div class="dac-filter dac-filter-section" data-filter="#latest-resources">
diff --git a/docs/html/distribute/stories/index.jd b/docs/html/distribute/stories/index.jd
index 1adc5ae..1745535 100644
--- a/docs/html/distribute/stories/index.jd
+++ b/docs/html/distribute/stories/index.jd
@@ -4,16 +4,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <p>Android developers, their apps, and their successes with Android and Google Play.</p>
 
 <section class="dac-section dac-small" id="latest-apps"><div class="wrap">
diff --git a/docs/html/index.jd b/docs/html/index.jd
index dc59b71..fe5dada 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -6,16 +6,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
   <div class="wrap" style="max-width:1000px;margin-top:0">
     <div class="col-7of16 col-push-8of16">
@@ -45,7 +35,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -73,28 +63,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}studio/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get Android Studio
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
deleted file mode 100644
index 3ceddf2..0000000
--- a/docs/html/jd_collections.js
+++ /dev/null
@@ -1,1935 +0,0 @@
-/*
- * THIS FILE IS DEPRECATED.
- *
- * Please add and edit resource collections in jd_extras_<lang>.js
- * where lang matches the language code appropriate for the resource.
- * Last sync'd with jd_extras_<lang>.js on 29 Apr 2016.
- *
- */
-var RESOURCE_COLLECTIONS = {
-  "index/carousel": {
-    "title": "",
-    "resources": [
-      "about/versions/lollipop.html"
-    ]
-  },
-  "index/primary": {
-    "title": "",
-    "resources": [
-      "training/building-wearables.html",
-      "training/material/index.html",
-      "studio/index.html"
-    ]
-  },
-  "index/secondary/carousel": {
-    "title": "",
-    "resources": [
-      "http://www.youtube.com/watch?v=9m6MoBM-sFI",
-      "http://www.youtube.com/watch?v=Pms0pcyPbAM",
-      "http://www.youtube.com/watch?v=e7t3svG9PTk",
-      "http://www.youtube.com/watch?v=J3IvOfvH1ys"
-    ]
-  },
-  "index/multiscreen": {
-    "title": "",
-    "resources": [
-      "wear/index.html",
-      "tv/index.html",
-      "auto/index.html"
-    ]
-  },
-  "index/primary/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/resources.html",
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-      "intl/zh-cn/distribute/tools/localization-checklist.html"
-    ]
-  },
-  "design/landing/latest": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=p4gmvHyuZzw",
-      "https://www.youtube.com/watch?v=YaG_ljfzeUw",
-      "https://www.youtube.com/watch?v=XOcCOBe8PTc"
-    ]
-  },
-  "design/landing/materialdesign": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/design/spec/animation/",
-      "https://www.google.com/design/spec/style/",
-      "https://www.google.com/design/spec/layout/",
-      "https://www.google.com/design/spec/components/",
-      "https://www.google.com/design/spec/patterns/",
-      "https://www.google.com/design/spec/usability/"
-    ]
-  },
-  "design/landing/pureandroid": {
-    "title": "",
-    "resources": [
-      "design/get-started/creative-vision.html",
-      "design/material/index.html",
-      "training/material/index.html",
-      "design/patterns/pure-android.html",
-      "design/patterns/new.html",
-      "design/devices.html"
-    ]
-  },
-  "design/landing/resources": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/design/spec/resources/color-palettes.html",
-      "https://www.google.com/design/spec/resources/layout-templates.html",
-      "https://www.google.com/design/spec/resources/sticker-sheets-icons.html",
-      "https://www.google.com/design/spec/resources/roboto-noto-fonts.html",
-      "https://www.google.com/design/icons/index.html",
-      "design/downloads/index.html#Wear"
-    ]
-  },
-  "develop/landing/mainlinks": {
-    "title": "",
-    "resources": [
-      "tools/studio/index.html",
-      "samples/new/index.html",
-      "tools/projects/templates.html"
-    ]
-  },
-  "develop/landing/latest": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/2015/04/new-android-code-samples.html",
-      "https://android-developers.blogspot.com/2015/04/android-support-library-221.html",
-      "https://android-developers.blogspot.com/2015/03/a-new-reference-app-for-multi-device.html"
-    ]
-  },
-  "develop/landing/devpatterns": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=kmUGLURRPkI",
-      "https://www.youtube.com/watch?v=HGElAW224dE",
-      "https://www.youtube.com/watch?v=zQekzaAgIlQ"
-    ]
-  },
-  "develop/landing/performance": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=fEEulSk1kNY",
-      "https://www.youtube.com/watch?v=-3ry8PxcJJA",
-      "https://www.youtube.com/watch?v=_kKTGK-Cb_4"
-    ]
-  },
-  "develop/landing/buildwithgoogle": {
-    "title": "",
-    "resources": [
-    ]
-  },
-  "develop/landing/ubicomp": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=AK38PJZmIW8&list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef",
-      "https://www.youtube.com/watch?v=6K_jxccHv5M&index=1&list=PLOU2XLYxmsILFBfx66ens76VMLMEPJAB0",
-      "https://www.youtube.com/watch?v=ctiaVxgclsg&list=PLWz5rJ2EKKc9BdE_PSLNIGjXXr3h_orXM"
-    ]
-  },
-  "develop/landing/tools": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=K2dodTXARqc&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-      "https://www.youtube.com/watch?v=cD7NPxuuXYY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-      "https://www.youtube.com/watch?v=JLLnhwtDoHw&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-      "https://www.youtube.com/watch?v=2I6fuD20qlY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-      "https://www.youtube.com/watch?v=5Be2mJzP-Uw&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX"
-    ]
-  },
-  "preview/landing/resources": {
-    "title": "",
-    "resources": [
-      "preview/overview.html",
-      "preview/api-overview.html",
-      "preview/behavior-changes.html",
-      "preview/setup-sdk.html",
-      "preview/samples.html",
-      "preview/support.html"
-    ]
-  },
-  "preview/landing/more": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=CsulIu3UaUM",
-      "preview/features/multi-window.html",
-      "preview/features/notification-updates.html",
-      "preview/features/background-optimization.html",
-      "preview/features/data-saver.html",
-      "preview/features/direct-boot.html",
-      "preview/features/icu4j-framework.html",
-      "preview/features/multilingual-support.html",
-      "preview/features/scoped-folder-access.html",
-      "preview/features/picture-in-picture.html",
-      "preview/features/tv-recording-api.html"
-    ]
-  },
-  "wear/preview/landing": {
-    "title": "",
-    "resources": [
-      "wear/preview/api-overview.html",
-      "wear/preview/downloads.html",
-      "wear/preview/start.html"
-    ]
-  },
-  "wear/preview/landing/resources": {
-    "title": "",
-    "resources": [
-      "wear/preview/features/complications.html",
-      "wear/preview/features/notifications.html",
-      "wear/preview/features/ui-nav-actions.html"
-    ]
-  },
-  "google/landing/services": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/analytics/devguides/collection/android/",
-      "https://developers.google.com/maps/documentation/android/",
-      "https://developers.google.com/identity/sign-in/android/",
-      "https://developers.google.com/mobile-ads-sdk/download",
-      "https://developers.google.com/cloud-messaging/gcm",
-      "https://developers.google.com/app-indexing/"
-    ]
-  },
-  "google/landing/videos": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=M3Udfu6qidk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-      "https://www.youtube.com/watch?v=FOn64iqlphk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-      "https://www.youtube.com/watch?v=F0Kh_RnSM0w&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-      "https://www.youtube.com/watch?v=fvtMtfCuEpw&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf"
-    ]
-  },
-  "google/landing/googleplay": {
-    "title": "",
-    "resources": [
-      "google/play/billing/index.html",
-      "google/play/billing/billing_subscriptions.html",
-      "google/play/developer-api.html"
-    ]
-  },
-  "develop/landing/courses": {
-    "title": "",
-    "resources": [
-      "https://www.udacity.com/course/ud849",
-      "https://www.udacity.com/course/ud853",
-      "https://www.udacity.com/course/ud825",
-      "https://www.udacity.com/android",
-      "https://www.udacity.com/course/ud855",
-      "https://www.udacity.com/course/ud875A",
-      "https://www.udacity.com/course/ud875B",
-      "https://www.udacity.com/course/ud875C",
-      "https://www.udacity.com/course/ud876--1",
-      "https://www.udacity.com/course/ud876--2",
-      "https://www.udacity.com/course/ud876--3",
-      "https://www.udacity.com/course/ud876--4",
-      "https://www.udacity.com/course/ud876--5",
-      "https://www.udacity.com/course/ud862",
-      "https://www.udacity.com/course/ud837",
-      "https://www.udacity.com/course/ud867"
-    ]
-  },
-  "distribute/landing/carousel": {
-    "title": "",
-    "resources": [
-    "distribute/googleplay/guide.html",
-    "https://www.youtube.com/watch?v=JrR6o5tYMWQ",
-    "https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
-    "https://www.youtube.com/watch?v=yJisuP94lHU",
-    ]
-  },
-  "distribute/landing/googleplay": {
-    "title": "",
-    "resources": [
-      "distribute/googleplay/about.html",
-      "distribute/googleplay/developer-console.html",
-      "distribute/googleplay/index.html#opportunities"
-    ]
-  },
-  "distribute/landing/more": {
-    "title": "",
-    "resources": [
-      "distribute/users/promote-with-ads.html",
-      "distribute/monetize/ads.html",
-      "distribute/analyze/index.html",
-      "distribute/engage/deep-linking.html",
-      "distribute/engage/easy-signin.html",
-      "https://cloud.google.com/docs/"
-    ]
-  },
-  "distribute/edu/videos/stories": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=Idu7VcTTXfk",
-      "https://www.youtube.com/watch?v=iokH4SAIfRw"
-    ]
-  },
-  "distribute/edu/videos/bestpractices": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=iulXz8QTD1g",
-      "https://www.youtube.com/watch?v=IKhU180eJMo",
-      "https://www.youtube.com/watch?v=_AZ6UcPz-_g",
-      "https://www.youtube.com/watch?v=Eh2adsAyTKc"
-    ]
-  },
-  "distribute/edu/videos/experience": {
-    "title": "",
-    "resources": [
-      "https://youtu.be/vzvpcEffvaE"
-    ]
-  },
-/*  "launch/static": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=1RIz-cmTQB4",
-      "https://www.youtube.com/watch?v=MVBMWDzyHAI",
-      "https://android-developers.blogspot.com/2013/11/app-translation-service-now-available.html",
-      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
-      "https://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
-      "distribute/essentials/quality/tablets.html",
-      "distribute/users/build-buzz.html",
-      "distribute/monetize/premium.html",
-      "distribute/monetize/freemium.html",
-      "distribute/monetize/ads.html",
-      "distribute/essentials/best-practices/apps.html",
-      "distribute/essentials/best-practices/games.html",
-      "distribute/users/know-your-user.html",
-      "distribute/googleplay/developer-console.html"
-    ]
-  }, */
-  "launch/static/ja": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=xelYnWcYkuE",
-      "https://www.youtube.com/playlist?list=PLCOC_kP3nqGIHEgwm9mybvA04Vn4Cg9nn",
-      "https://googledevjp.blogspot.jp/2014/12/android-wear.html",
-      "https://googledevjp.blogspot.jp/2014/12/android-studio-10.html",
-      "https://googledevjp.blogspot.jp/2014/12/google-play-65.html",
-      "intl/ja/distribute/googleplay/developer-console.html#alpha-beta",
-      "intl/ja/distribute/googleplay/guide.html",
-      "intl/ja/distribute/essentials/quality/core.html",
-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ja",
-      "intl/ja/support.html",
-      "intl/ja/distribute/essentials/quality/wear.html",
-      "intl/ja/training/tv/start/index.html",
-      "https://googleforwork-japan.blogspot.jp/2014/12/gcp-google-cloud-platform-rpg-gcp.html",
-      "intl/ja/distribute/monetize/ads.html"
-    ]
-  },
-  "launch/static/ko": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=7X9Ue0Nfdh4&index=2&list=PL_WJkTbDHdBksDBRoqfeyLchEQqBAOlNl",
-      "https://www.youtube.com/watch?v=83FpwuschCQ",
-      "https://googledevkr.blogspot.com/2014/11/android50guidefordevelopers.html",
-      "https://googledevkr.blogspot.com/2014/10/material-design-on-android-checklist.html",
-      "https://googledevkr.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html",
-      "intl/ko/distribute/googleplay/developer-console.html#alpha-beta",
-      "intl/ko/distribute/googleplay/guide.html",
-      "intl/ko/distribute/essentials/quality/core.html",
-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ko",
-      "intl/ko/support.html",
-      "intl/ko/distribute/essentials/quality/wear.html",
-      "intl/ko/tv/index.html",
-      "intl/ko/google/play-services/games.html",
-      "intl/ko/distribute/monetize/ads.html"
-    ]
-  },
-  "distribute/gp/gplanding": {
-    "resources": [
-      "distribute/googleplay/about.html",
-      "distribute/googleplay/start.html",
-      "distribute/googleplay/developer-console.html"
-    ]
-  },
-  "distribute/gp/gpfelanding": {
-    "resources": [
-      "distribute/googleplay/wear.html",
-      "distribute/googleplay/tv.html",
-      "distribute/googleplay/auto.html",
-      "distribute/googleplay/families/about.html",
-      "distribute/googleplay/work/about.html",
-      "distribute/googleplay/edu/about.html",
-      "distribute/googleplay/cast.html",
-      "distribute/googleplay/cardboard.html",
-      "distribute/googleplay/guide.html"
-    ]
-  },
-  "distribute/googleplay/gpfw": {
-    "resources": [
-      "https://www.android.com/work/",
-      "https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-      "work/index.html"
-    ]
-  },
-  "distribute/essentials": {
-    "resources": [
-      "distribute/essentials/quality/core.html",
-      "distribute/essentials/quality/tablets.html",
-      "distribute/essentials/quality/tv.html",
-      "distribute/essentials/quality/wear.html",
-      "distribute/essentials/quality/auto.html",
-      "distribute/essentials/quality/billions.html"
-    ]
-  },
-  "distribute/essentials/zhcn": {
-    "resources": [
-      "intl/zh-cn/distribute/essentials/quality/core.html",
-      "intl/zh-cn/distribute/essentials/quality/tablets.html",
-      "distribute/essentials/quality/tv.html",
-      "distribute/essentials/quality/wear.html",
-      "https://developers.google.com/edu/guidelines",
-      "distribute/essentials/optimizing-your-app.html"
-    ]
-  },
-  "distribute/users": {
-    "title": "",
-    "resources": [
-      "distribute/users/your-listing.html",
-      "distribute/users/promote-with-ads.html",
-      "distribute/googleplay/index.html#opportunities",
-      "distribute/analyze/improve-roi.html",
-      "distribute/users/expand-to-new-markets.html",
-      "distribute/analyze/index.html",
-      "distribute/users/app-invites.html",
-      "distribute/users/ota-installs.html",
-      "distribute/users/youtube.html",
-      "distribute/users/house-ads.html",
-      "distribute/users/experiments.html",
-      "distribute/users/user-acquisition.html",
-      "distribute/users/banners.html",
-      "distribute/users/beta.html"
-    ]
-  },
-  "distribute/engagelanding": {
-    "resources": [
-      "distribute/engage/intents.html",
-      "distribute/engage/widgets.html",
-      "distribute/engage/translate.html",
-      "distribute/engage/notifications.html",
-      "distribute/engage/deep-linking.html",
-      "distribute/engage/ads.html",
-      "distribute/engage/game-services.html",
-      "distribute/engage/easy-signin.html",
-      "distribute/analyze/build-better-apps.html",
-      "distribute/engage/gcm.html",
-      "distribute/engage/beta.html",
-      "distribute/engage/nearby.html"
-    ]
-  },
-  "distribute/monetize": {
-    "resources": [
-      "distribute/monetize/premium.html",
-      "distribute/monetize/freemium.html",
-      "distribute/monetize/subscriptions.html",
-      "distribute/monetize/ads.html",
-      "distribute/monetize/ecommerce.html",
-      "distribute/monetize/payments.html",
-      "distribute/monetize/conversions.html",
-      "distribute/analyze/understand-user-value.html",
-    ]
-  },
-  "distribute/analyzelanding": {
-    "resources": [
-      "distribute/analyze/start.html",
-      "distribute/analyze/measure.html",
-      "distribute/analyze/understand-user-value.html",
-      "distribute/analyze/improve-roi.html",
-      "distribute/analyze/build-better-apps.html",
-      "distribute/analyze/google-services.html"
-    ]
-  },
-  "distribute/analyzestart": {
-    "resources": [
-      "https://analyticsacademy.withgoogle.com/course04",
-      "google/play-services/index.html",
-      "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
-      "https://developers.google.com/analytics/devguides/collection/android/",
-      "https://www.google.com/tagmanager/",
-      "https://github.com/googleanalytics/google-analytics-plugin-for-unity"
-    ]
-  },
-  "distribute/analyzemeasure": {
-    "resources": [
-
-      "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
-      "https://support.google.com/analytics/answer/1032415",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/events",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/customdimsmets",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/user-id"
-    ]
-  },
-  "distribute/analyzeunderstand": {
-    "resources": [
-      "https://developers.google.com/analytics/devguides/collection/android/v4/display-features",
-      "https://support.google.com/analytics/answer/3123906",
-      "https://support.google.com/analytics/answer/2568874?ref_topic=6012392",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
-      "https://support.google.com/analytics/answer/1032415",
-    ]
-  },
-  "distribute/analyzeimprove": {
-    "resources": [
-
-      "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns",
-      "https://support.google.com/analytics/answer/2956981",
-      "https://support.google.com/analytics/answer/1033961",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder",
-      "https://developers.google.com/analytics/solutions/mobile-campaign-deep-link"
-    ]
-  },
-  "distribute/analyzebuild": {
-    "resources": [
-      "https://support.google.com/tagmanager/answer/6003007",
-      "https://support.google.com/analytics/answer/2785577",
-      "https://support.google.com/analytics/answer/1151300"
-    ]
-  },
-  "distribute/analyzeact": {
-    "resources": [
-      "https://support.google.com/analytics/answer/2611268",
-      "https://support.google.com/analytics/answer/1033961",
-      "https://support.google.com/admob/answer/3508177",
-      "https://support.google.com/analytics/answer/2956981",
-      "https://support.google.com/tagmanager/answer/6003007"
-    ]
-  },
-  "distribute/essentials/guidelines": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/quality/core.html",
-      "distribute/essentials/quality/tablets.html",
-      "distribute/essentials/quality/wear.html",
-      "distribute/essentials/quality/tv.html",
-      "distribute/essentials/quality/auto.html",
-      "distribute/essentials/quality/billions.html"
-    ]
-  },
-  "distribute/essentials/tools": {
-    "title": "",
-    "resources": [
-      "distribute/tools/launch-checklist.html",
-      "distribute/tools/localization-checklist.html",
-      "https://support.google.com/googleplay/android-developer",
-      "distribute/tools/promote/brand.html",
-      "distribute/tools/promote/device-art.html",
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/linking.html",
-      "distribute/tools/open-distribution.html",
-      "about/dashboards/index.html"
-    ]
-  },
-  "distribute/tools/checklists": {
-    "title": "",
-    "resources": [
-      "distribute/tools/launch-checklist.html",
-      "distribute/tools/localization-checklist.html"
-    ]
-  },
-  "distribute/tools/checklists/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-      "intl/zh-cn/distribute/tools/localization-checklist.html"
-    ]
-  },
-  "distribute/tools/promote": {
-    "resources": [
-      "distribute/tools/promote/device-art.html",
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/linking.html"
-    ]
-  },
-  "distribute/tools/promote/zhcn": {
-    "resources": [
-      "intl/zh-cn/distribute/tools/promote/device-art.html",
-      "https://play.google.com/intl/en_us/badges/",
-      "intl/zh-cn/distribute/tools/promote/linking.html"
-    ]
-  },
-  "distribute/tools/support": {
-    "title": "Google Play",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer",
-      "https://support.google.com/googleplay/android-developer/answer/4430948",
-      "support.html"
-    ]
-  },
-  "distribute/tools/support/zhcn": {
-    "title": "Google Play",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
-      "support.html"
-    ]
-  },
-  "distribute/tools/news": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/",
-      "https://plus.google.com/+AndroidDevelopers/"
-    ]
-  },
-  "distribute/tools/more": {
-    "title": "Google Play",
-    "resources": [
-      "distribute/tools/promote/brand.html",
-      "distribute/tools/open-distribution.html",
-      "about/dashboards/index.html"
-    ]
-  },
-  "distribute/tools/more/zhcn": {
-    "title": "Google Play",
-    "resources": [
-      "intl/zh-cn/distribute/tools/promote/brand.html",
-      "distribute/tools/open-distribution.html",
-      "about/dashboards/index.html"
-    ]
-  },
-  "distribute/googleplay": {
-    "title": "Google Play",
-    "resources": [
-      "distribute/googleplay/developer-console.html",
-      "distribute/essentials/best-practices/apps.html",
-      "distribute/tools/launch-checklist.html",
-      "distribute/essentials/best-practices/games.html",
-    ]
-  },
-  "distribute/googleplay/gettingstarted": {
-    "title": "Get Started",
-    "resources": [
-      "distribute/googleplay/developer-console.html",
-      "https://support.google.com/googleplay/android-developer/answer/113468",
-      "https://support.google.com/googleplay/android-developer/answer/138294",
-      "https://support.google.com/googleplay/android-developer"
-    ]
-  },
-  "distribute/googleplay/developerconsole/related": {
-    "title": "Developer Console",
-    "resources": [
-      "google/play/billing/index.html",
-      "https://support.google.com/googleplay/android-developer/answer/138294"
-    ]
-  },
-  "distribute/googleplay/beta": {
-    "title": "Alpha and Beta Testing",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/3131213",
-      "https://support.google.com/googleplay/android-developer/answer/3131213#games",
-      "distribute/googleplay/experiments.html"
-    ]
-  },
-  "distribute/googleplay/experiments/successes": {
-    "title": "Store Listing Experiment successes",
-    "resources": [
-    ]
-  },
-  "distribute/googleplay/experiments/related": {
-    "title": "Store Listing Experiments",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/6227309",
-      "https://www.youtube.com/watch?v=B6ydLpkhq04",
-      "https://support.google.com/tagmanager/answer/6003007"
-    ]
-  },
-  "distribute/googleplay/banners/related": {
-    "title": "App Install Banners",
-    "resources": [
-      "https://developers.google.com/web/updates/2015/03/increasing-engagement-with-app-install-banners-in-chrome-for-android#native"
-    ]
-  },
-  "distribute/googleplay/useracquisition/related": {
-    "title": "User Acquisition",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/6263332"
-    ]
-  },
-  "distribute/googleplay/cast": {
-    "title": "Google Cast",
-    "resources": [
-      "https://developers.google.com/cast/docs/ux_guidelines",
-      "https://developers.google.com/cast/docs/android_sender",
-      "https://www.github.com/googlecast"
-    ]
-  },
-  "distribute/googleplay/cardboard": {
-    "title": "Google Cast",
-    "resources": [
-      "https://www.google.com/get/cardboard/get-cardboard/",
-      "https://developers.google.com/cardboard/android/download",
-      "https://www.google.com/design/spec-vr"
-    ]
-  },
-  "distribute/googleplay/gpfe/highlight": {
-    "title": "About Google Play for Education",
-    "resources": [
-      "https://youtu.be/vzvpcEffvaE"
-    ]
-  },
-  "distribute/googleplay/gpfe/dev/about": {
-    "title": "About Google Play for Education / Developers",
-    "resources": [
-      "distribute/googleplay/edu/start.html",
-      "https://developers.google.com/edu/guidelines",
-      "https://developers.google.com/edu/faq",
-      "distribute/essentials/quality/tablets.html",
-      "https://developers.google.com/edu/",
-      "https://www.google.com/edu/tablets/#tablets-family"
-    ]
-  },
-  "distribute/googleplay/gpfe/dev": {
-    "title": "About Google Play for Education / Developers",
-    "resources": [
-      "distribute/googleplay/edu/about.html",
-      "https://developers.google.com/edu/guidelines",
-      "distribute/essentials/quality/tablets.html",
-      "distribute/googleplay/developer-console.html",
-      "https://play.google.com/about/developer-distribution-agreement-addendum.html",
-    ]
-  },
-  "distribute/googleplay/aboutgpfe/educators/about": {
-    "title": "About Google Play for Education / Educators",
-    "resources": [
-      "https://www.google.com/edu/tablets/",
-      "https://www.youtube.com/watch?v=haEmsMo0f3w"
-    ]
-  },
-  "distribute/googleplay/aboutgpfe/educators": {
-    "title": "About Google Play for Education / Educators",
-    "resources": [
-      "https://www.google.com/edu/tablets/",
-      "https://youtu.be/vzvpcEffvaE"
-    ]
-  },
-  "distribute/googleplay/gettingstartedgpfe/educators": {
-    "title": "About Google Play for Education / Educators",
-    "resources": [
-      "https://www.google.com/edu/tablets/",
-      "https://youtu.be/vzvpcEffvaE"
-    ]
-  },
-  "distribute/essentials/eduessentials/developers": {
-    "title": "",
-    "resources": [
-      "distribute/googleplay/developer-console.html",
-      "distribute/googleplay/edu/start.html",
-      "https://developers.google.com/edu/faq"
-    ]
-  },
-  "distribute/essentials/eduessentials/educators": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/edu/tablets/",
-      "distribute/essentials/quality/tablets.html",
-    ]
-  },
-  "distribute/essentials/optimizing": {
-    "title": "Optimizing Your App",
-    "resources": [
-      "design/index.html",
-      "training/articles/perf-anr.html",
-      "https://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html"
-     ]
-  },
-  "distribute/users/appinvites": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/app-invites/",
-      "https://developers.google.com/identity/sign-in/android/",
-      "https://developers.google.com/app-indexing/"
-    ]
-  },
-  "distribute/users/knowyouruser": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/optimizing-your-app.html",
-      "http://www.youtube.com/watch?v=RRelFvc6Czo",
-      "distribute/stories/games/rvappstudios-zombie.html"
-    ]
-  },
-  "distribute/users/promotewithads": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/adwords/answer/6032059",
-      "https://support.google.com/adwords/answer/6032073",
-      "https://support.google.com/adwords/answer/6167164",
-      "https://support.google.com/adwords/answer/6167162"
-    ]
-  },
-  "distribute/users/nearby": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/nearby/",
-      "https://www.youtube.com/watch?v=hultDpBS22s",
-      "https://developers.google.com/beacons"
-    ]
-  },
-  "distribute/users/buildbuzz": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/linking.html",
-      "distribute/tools/promote/device-art.html",
-      "https://plus.google.com/+GooglePlay"
-    ]
-  },
-  "distribute/users/createagreatlisting": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/1078870",
-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
-      "distribute/tools/launch-checklist.html",
-      "https://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
-      "https://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
-      "https://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html"
-    ]
-  },
-  "distribute/users/buildcommunity": {
-    "title": "",
-    "resources": [
-      "distribute/googleplay/developer-console.html",
-      "https://support.google.com/groups/answer/46601",
-      "https://support.google.com/plus/topic/2888488",
-      "https://www.youtube.com/yt/dev/"
-    ]
-  },
-  "distribute/users/appindexing": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/app-indexing/",
-      "https://developers.google.com/app-indexing/webmasters/details",
-      "distribute/engage/deep-linking.html",
-      "training/app-indexing/index.html"
-    ]
-  },
-  "distribute/users/otas": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/identity/sign-in/android/",
-      "https://developers.google.com/+/features/play-installs",
-      "https://developers.google.com/+/features/analytics"
-    ]
-  },
-  "distribute/users/houseads": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/admob/topic/2784623",
-      "https://developers.google.com/mobile-ads-sdk/download",
-      "https://support.google.com/googleplay/android-developer/topic/2985714",
-      "https://analyticsacademy.withgoogle.com/mobile-app",
-      "https://support.google.com/analytics/answer/2611404",
-      "https://support.google.com/admob/answer/3111064"
-    ]
-  },
-  "distribute/users/youtube": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/youtube/answer/6140493",
-      "https://support.google.com/youtube/answer/2797387"
-    ]
-  },
-  "distribute/toolsreference/bestpractices/apps": {
-    "title": "",
-    "resources": [
-      "distribute/googleplay/developer-console.html",
-      "https://android-developers.blogspot.com/"
-    ]
-  },
-  "distribute/toolsreference/bestpractices/games": {
-    "title": "",
-    "resources": [
-      "google/play-services/games.html",
-      "https://android-developers.blogspot.com/",
-      "distribute/googleplay/developer-console.html",
-      "https://www.youtube.com/watch?v=1RIz-cmTQB4"
-    ]
-  },
-  "distribute/essentials/corequalityguidelines/visualdesign": {
-    "title": "",
-    "resources": [
-      "design/index.html",
-      "design/patterns/navigation.html",
-      "design/patterns/actionbar.html",
-      "design/style/iconography.html"
-    ]
-  },
-  "distribute/essentials/corequalityguidelines/functionality": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
-      "guide/components/tasks-and-back-stack.html",
-      "training/basics/activity-lifecycle/recreating.html"
-    ]
-  },
-  "distribute/essentials/tvqualityguidelines/visualdesign": {
-    "title": "",
-    "resources": [
-      "design/tv/index.html",
-      "training/tv/start/index.html"
-    ]
-  },
-  "distribute/essentials/tvqualityguidelines/functionality": {
-    "title": "",
-    "resources": [
-      "training/tv/start/hardware.html",
-      "training/tv/games/index.html"
-    ]
-  },
-  "distribute/essentials/wearqualityguidelines/visualdesign": {
-    "title": "",
-    "resources": [
-      "design/wear/index.html",
-      "training/building-wearables.html",
-      "training/wearables/ui/index.html"
-    ]
-  },
-  "distribute/essentials/wearqualityguidelines/functionality": {
-    "title": "",
-    "resources": [
-      "training/wearables/notifications/index.html",
-      "training/wearables/apps/index.html",
-      "training/wearables/notifications/voice-input.html"
-    ]
-  },
-    "distribute/essentials/autoqualityguidelines/visualdesign": {
-    "title": "",
-    "resources": [
-      "training/auto/messaging/index.html",
-      "training/auto/start/index.html"
-    ]
-  },
-  "distribute/essentials/core/performance": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html",
-      "training/articles/perf-anr.html",
-      "https://android-developers.blogspot.com/2010/07/multithreading-for-performance.html"
-    ]
-  },
-  "distribute/essentials/core/play": {
-    "title": "",
-    "resources": [
-      "distribute/tools/launch-checklist.html",
-      "https://play.google.com/about/developer-content-policy.html?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
-      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans"
-    ]
-  },
-  "distribute/essentials/core/play/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-      "https://play.google.com/about/developer-content-policy.html",
-      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
-      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/optimize": {
-    "title": "",
-    "resources": [
-      "design/style/metrics-grids.html",
-      "design/style/devices-displays.html",
-      "guide/practices/screens_support.html",
-      //"guide/practices/screens_support.html#ConfigurationExamples",
-    ]
-  },
-  "distribute/essentials/tabletguidelines/extrascreen": {
-    "title": "",
-    "resources": [
-      "design/patterns/multi-pane-layouts.html",
-      "training/design-navigation/multiple-sizes.html",
-      "training/multiscreen/index.html",
-    ]
-  },
-  "distribute/essentials/tabletguidelines/assets": {
-    "title": "",
-    "resources": [
-      "design/style/iconography.html",
-      "guide/topics/resources/providing-resources.html",
-      "guide/practices/screens_support.html",
-      "training/basics/supporting-devices/screens.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/fonts": {
-    "title": "",
-    "resources": [
-      "design/style/metrics-grids.html",
-      "design/style/typography.html",
-      "guide/practices/screens_support.html",
-      "training/multiscreen/screendensities.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/widgets": {
-    "title": "",
-    "resources": [
-      "guide/topics/appwidgets/index.html#MetaData",
-      "guide/topics/appwidgets/index.html",
-      "design/patterns/widgets.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/versions": {
-    "title": "",
-    "resources": [
-      "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
-      "guide/topics/manifest/uses-sdk-element.html",
-      "training/basics/supporting-devices/platforms.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/hardware": {
-    "title": "",
-    "resources": [
-      "guide/topics/manifest/uses-feature-element.html",
-      "guide/topics/manifest/uses-feature-element.html#testing"
-    ]
-  },
- "distribute/essentials/tabletguidelines/tabletscreens": {
-    "title": "",
-    "resources": [
-      "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
-      "guide/practices/screens_support.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/showcase": {
-    "title": "",
-    "resources": [
-      "distribute/tools/launch-checklist.html",
-      "https://play.google.com/apps/publish/",
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/device-art.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/showcase/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-      "https://play.google.com/apps/publish/?hl=zh-Hans",
-      "https://play.google.com/intl/en_us/badges/",
-      "intl/zh-cn/distribute/tools/promote/device-art.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/googleplay": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
-      "google/play/filters.html"
-    ]
-  },
- "distribute/essentials/billionsquality/connectivity": {
-    "title": "",
-    "resources": [
-      "training/basics/network-ops/managing.html",
-      "training/monitoring-device-state/connectivity-monitoring.html",
-      "guide/topics/providers/content-providers.html"
-    ]
-  },
-  "distribute/essentials/billionsquality/capability": {
-    "title": "",
-    "resources": [
-      "guide/practices/screens_support.html",
-      "training/multiscreen/screendensities.html",
-      "training/articles/memory.html"
-    ]
-  },
-  "distribute/essentials/billionsquality/cost": {
-    "title": "",
-    "resources": [
-      "https://medium.com/@wkalicinski/smallerapk-part-6-image-optimization-zopfli-webp-4c462955647d#.23hlddo3x",
-      "training/basics/network-ops/managing.html"
-    ]
-  },
-  "distribute/essentials/billionsquality/consumption": {
-    "title": "",
-    "resources": [
-      "training/efficient-downloads/efficient-network-access.html",
-      "training/monitoring-device-state/index.html"
-    ]
-  },
-  "distribute/essentials/billionsquality/content": {
-    "title": "",
-    "resources": [
-      "training/material/animations.html#Touch",
-      "training/articles/perf-anr.html",
-      "training/improving-layouts/index.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/quality/core.html",
-      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
-      "distribute/tools/launch-checklist.html",
-      "distribute/tools/promote/device-art.html"
-    ]
-  },
-  "distribute/getusers/notifications": {
-    "title": "",
-    "resources": [
-      "distribute/engage/gcm.html",
-      "https://play.google.com/about/developer-content-policy.html"
-    ]
-  },
-  "distribute/engage/analytics": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/analytics/mobile/",
-      "https://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html",
-      "https://developers.google.com/analytics/devguides/collection/android/"
-    ]
-  },
-  "distribute/engage/widgets": {
-    "title": "",
-    "resources": [
-      "design/patterns/widgets.html",
-      "guide/topics/appwidgets/index.html"
-    ]
-  },
-  "distribute/engage/translate": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/l10n/answer/6359997"
-    ]
-  },
-  "distribute/engage/reengage": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/adwords/answer/6032073",
-      "distribute/engage/deep-linking.html",
-      "https://support.google.com/adwords/answer/6167162",
-      "distribute/users/promote-with-ads.html"
-    ]
-  },
-  "distribute/engage/appindexing": {
-    "title": "",
-    "resources": [
-      "distribute/engage/intents.html",
-      "distribute/engage/deep-linking.html",
-      "training/app-indexing/index.html"
-    ]
-  },
-  "distribute/engage/intents": {
-    "title": "",
-    "resources": [
-      "guide/components/intents-filters.html",
-      "distribute/engage/deep-linking.html",
-      "distribute/engage/ads.html"
-    ]
-  },
-  "distribute/getusers/expandnewmarkets": {
-    "title": "",
-    "resources": [
-      "distribute/tools/localization-checklist.html",
-      "https://support.google.com/googleplay/android-developer/table/3541286",
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/device-art.html",
-      "https://www.youtube.com/watch?v=SkHHPf3EdzE"
-    ]
-  },
-  "distribute/engage/gcm": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/cloud-messaging/gcm",
-      "https://developers.google.com/cloud-messaging/android/client",
-    ]
-  },
-  "distribute/engage/gamesservices/related": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/games/services/",
-      "distribute/analyze/start.html",
-      "distribute/googleplay/cardboard.html",
-      "https://www.google.com/admob/"
-    ]
-  },
-  "distribute/engage/gplus": {
-    "title": "",
-    "resources": [
-      "distribute/users/ota-installs.html",
-      "https://developers.google.com/identity/sign-in/android/people",
-      "https://developers.google.com/+/mobile/android/"
-    ]
-  },
-  "distribute/engage/community": {
-    "title": "",
-    "resources": [
-      "distribute/users/build-community.html",
-      "distribute/engage/video.html"
-    ]
-  },
-  "distribute/engage/deeplinks": {
-    "title": "",
-    "resources": [
-      "distribute/engage/easy-signin.html",
-      "https://developers.google.com/app-indexing/",
-      "https://developers.google.com/+/mobile/android/share/interactive-post"
-    ]
-  },
-  "distribute/engage/appupdates": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/optimizing-your-app.html",
-      "distribute/tools/launch-checklist.html",
-      "distribute/googleplay/developer-console.html"
-    ]
-  },
-  "distribute/engage/video/more": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/yt/dev/",
-      "distribute/essentials/best-practices/games.html",
-      "https://www.youtube.com/watch?v=RRelFvc6Czo"
-    ]
-  },
-  "distribute/engage/community": {
-    "title": "",
-    "resources": [
-      "distribute/users/build-community.html",
-      "distribute/engage/video.html"
-    ]
-  },
-  "distribute/engage/kiwi": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=WWArLD6nqrk"
-    ]
-  },
-  "distribute/toolsreference/gpfefaq": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/edu/tablets/",
-      "distribute/googleplay/edu/start.html",
-      "https://play.google.com/about/developer-distribution-agreement-addendum.html",
-      "distribute/essentials/quality/core.html",
-      "distribute/essentials/quality/tablets.html"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/identifylocales": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/138294"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/identifylocales/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans"
-    ]
-  },
-  "distribute/tools/loc/designforloc": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
-      "guide/topics/resources/string-resource.html#Plurals",
-      "guide/topics/resources/string-resource.html",
-      "reference/java/util/Locale.html"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/managestrings": {
-    "title": "",
-    "resources": [
-      "guide/topics/resources/string-resource.html",
-      "design/style/writing.html",
-      "https://en.wikipedia.org/wiki/XLIFF"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/managestrings/zhcn": {
-    "title": "",
-    "resources": [
-      "guide/topics/resources/string-resource.html",
-      "intl/zh-cn/design/style/writing.html",
-      "https://en.wikipedia.org/wiki/XLIFF"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/preplaunch": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/device-art.html"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/preplaunch/zhcn": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "intl/zh-cn/distribute/tools/promote/device-art.html"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/supportlaunch": {
-    "title": "",
-    "resources": [
-      "distribute/tools/launch-checklist.html",
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/supportlaunch/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/understanding": {
-    "title": "",
-    "resources": [
-      "tools/publishing/publishing_overview.html",
-      "tools/publishing/preparing.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/policies": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/4430948",
-      "https://support.google.com/googleplay/android-developer/topic/2364761",
-      "https://support.google.com/googleplay/android-developer"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/quality": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/quality/core.html",
-      "distribute/essentials/quality/tablets.html",
-      "https://developers.google.com/edu/guidelines"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/rating": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/188189",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/country": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/138294"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/size": {
-    "title": "",
-    "resources": [
-      "google/play/expansion-files.html",
-      "tools/help/proguard.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/platform": {
-    "title": "",
-    "resources": [
-      "guide/practices/screens_support.html",
-      "about/dashboards/index.html",
-      "guide/topics/manifest/uses-sdk-element.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/price": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/table/3541286",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/purchasemethod": {
-    "title": "",
-    "resources": [
-      "google/play/billing/index.html",
-      "google/play/billing/billing_subscriptions.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/setprice": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/1169947",
-      "https://support.google.com/googleplay/android-developer/answer/138412",
-      "https://support.google.com/googleplay/android-developer/answer/112622",
-      "https://support.google.com/googleplay/android-developer/answer/138000"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/localization": {
-    "title": "",
-    "resources": [
-      "distribute/tools/localization-checklist.html",
-      "https://support.google.com/l10n/answer/6359997"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/graphics": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/1078870",
-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/productdetails": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/113475",
-      "https://support.google.com/googleplay/android-developer/answer/1078870"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/badges": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/linking.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/finalchecks": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/about/developer-content-policy.html",
-      "https://support.google.com/googleplay/android-developer/answer/113476",
-      "support.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/afterlaunch": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/113477",
-      "https://support.google.com/googleplay/android-developer/answer/1153479",
-      "https://support.google.com/payments/answer/2741495",
-      "distribute/essentials/optimizing-your-app.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/understanding/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/tools/publishing/publishing_overview.html",
-      "intl/zh-cn/tools/publishing/preparing.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/policies/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/topic/2364761?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer?hl=zh-Hans"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/quality/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/essentials/quality/core.html",
-      "intl/zh-cn/distribute/essentials/quality/tablets.html",
-      "https://developers.google.com/edu/guidelines?hl=zh-Hans"
-    ]
-  },
-
-  "distribute/toolsreference/launchchecklist/rating/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/country/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/size/zhcn": {
-    "title": "",
-    "resources": [
-      "google/play/expansion-files.html",
-      "intl/zh-cn/tools/help/proguard.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/price/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/table/3541286?hl=zh-Hans",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/purchasemethod/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/google/play/billing/index.html",
-      "google/play/billing/billing_subscriptions.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/setprice/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/1169947?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/138412?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/112622?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/138000?hl=zh-Hans"
-    ]
-  },
-  "distribute/stories/localization": {
-    "title": "",
-    "resources": [
-      "distribute/stories/games/rvappstudios-zombie.html",
-      "distribute/stories/games/g4a-indian-rummy.html",
-      "distribute/stories/apps/sayhi.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/localization/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/tools/localization-checklist.html",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/graphics/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/productdetails/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/113475?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/badges/zhcn": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "intl/zh-cn/distribute/tools/promote/linking.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/finalchecks/zhcn": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/about/developer-content-policy.html",
-      "https://support.google.com/googleplay/android-developer/answer/113476?hl=zh-Hans",
-      "support.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/afterlaunch/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/1153479?hl=zh-Hans",
-      "https://support.google.com/payments/answer/2741495?hl=zh-Hans",
-      "distribute/essentials/optimizing-your-app.html"
-    ]
-  },
-  "distribute/monetize/premium": {
-    "title": "",
-    "resources": [
-      "google/play/billing/index.html",
-      "https://support.google.com/googleplay/android-developer/answer/4407611"
-    ]
-  },
-  "distribute/monetize/freemium": {
-    "title": "",
-    "resources": [
-      "google/play/billing/index.html",
-      "https://support.google.com/googleplay/android-developer/answer/4407611"
-    ]
-  },
-  "distribute/monetize/subscriptions": {
-    "title": "",
-    "resources": [
-      "google/play/billing/billing_subscriptions.html",
-      "https://support.google.com/googleplay/android-developer/answer/4407611"
-    ]
-  },
-  "distribute/monetize/ecommerce": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/wallet/instant-buy/",
-      "https://support.google.com/googleplay/android-developer/answer/4407611"
-    ]
-  },
-  "distribute/monetize/advertising": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/ads/admob/#subid=us-en-et-dac",
-      "https://www.google.com/doubleclick/publishers/small-business/index.html",
-      "https://support.google.com/googleplay/android-developer/topic/2985714",
-      "training/monetization/ads-and-ux.html"
-    ]
-  },
-  "distribute/monetize/admob": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/admob/topic/2784623",
-      "https://admob.blogspot.com/",
-      "https://analyticsacademy.withgoogle.com/mobile-app",
-      "https://www.udacity.com/courses/ud876-3"
-    ]
-  },
-  "distribute/monetize/paymentmethods": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/about/giftcards/",
-      "https://support.google.com/googleplay/answer/2651410"
-    ]
-  },
-  "distribute/monetize/conversions": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/adwords/answer/2471188",
-      "https://developers.google.com/app-conversion-tracking/",
-      "https://support.google.com/analytics/answer/2611404",
-      "https://support.google.com/adwords/answer/1704341"
-    ]
-  },
-  "autolanding": {
-    "title": "",
-    "resources": [
-      "auto/index.html",
-      "design/auto/index.html",
-      "training/auto/index.html"
-    ]
-  },
-  "tvlanding": {
-    "title": "",
-    "resources": [
-      "tv/index.html",
-      "design/tv/index.html",
-      "training/tv/index.html"
-    ]
-  },
-  "wearlanding": {
-    "title": "",
-    "resources": [
-      "design/wear/index.html",
-      "training/building-wearables.html",
-      "training/wearables/ui/index.html"
-    ]
-  },
-  "design/auto/auto_ui_guidelines": {
-    "title": "",
-    "resources": [
-      "shareables/auto/AndroidAuto-audio-apps.pdf",
-      "shareables/auto/AndroidAuto-messaging-apps.pdf",
-      "shareables/auto/AndroidAuto-custom-colors.pdf"
-    ]
-  },
-  "training/auto/overview": {
-    "title": "",
-    "resources": [
-      "training/auto/start/index.html",
-      "design/auto/index.html",
-      "shareables/auto/AndroidAuto-custom-colors.pdf"
-    ]
-  },
-  "training/auto/messaging": {
-    "title": "",
-    "resources": [
-      "training/auto/messaging/index.html",
-      "shareables/auto/AndroidAuto-messaging-apps.pdf",
-      "samples/MessagingService/index.html"
-    ]
-  },
-  "training/auto/media": {
-    "title": "",
-    "resources": [
-      "training/auto/audio/index.html",
-      "shareables/auto/AndroidAuto-audio-apps.pdf",
-      "samples/MediaBrowserService/index.html"
-    ]
-  },
-  "training/auto/distribute": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/quality/auto.html",
-      "distribute/googleplay/auto.html"
-    ]
-  },
-  "training/testing/overview": {
-    "title": "",
-    "resources": [
-      "training/testing/start/index.html",
-      "tools/testing/testing_android.html",
-      "https://www.youtube.com/watch?v=vdasFFfXKOY"
-    ]
-  },
-  "training/testing/tools": {
-    "title": "",
-    "resources": [
-      "tools/testing-support-library/index.html",
-      "tools/help/monkey.html",
-      "tools/help/monkeyrunner_concepts.html",
-      "tools/testing/testing_otheride.html",
-      "https://source.android.com/devices/tech/debug/dumpsys.html"
-    ]
-  },
-  "training/testing/techniques": {
-    "title": "",
-    "resources": [
-      "training/testing/ui-testing/index.html",
-      "training/testing/unit-testing/index.html",
-      "training/testing/performance.html"
-    ]
-  },
-  "training/testing/resources": {
-    "title": "",
-    "resources": [
-      "https://github.com/googlesamples/android-testing",
-      "https://www.youtube.com/watch?v=2I6fuD20qlY",
-      "https://codelabs.developers.google.com/codelabs/android-testing/index.html",
-      "https://github.com/googlesamples/android-testing-templates",
-      "https://google.github.io/android-testing-support-library"
-    ]
-  },
-  "distribute/stories/games": {
-    "title": "",
-    "resources": [
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebel_DoctorWhoLegacy_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf"
-    ]
-  },
-  "overview/zhcn/1": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/essentials/quality/core.html",
-      "intl/zh-cn/distribute/essentials/quality/tablets.html",
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-      "intl/zh-cn/tools/publishing/publishing_overview.html",
-      "intl/zh-cn/distribute/tools/localization-checklist.html"
-    ]
-  },
-    "overview/zhcn/2": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/google/play/billing/index.html",
-      "intl/zh-cn/google/play/billing/api.html",
-      "intl/zh-cn/google/play/billing/billing_admin.html",
-      "intl/zh-cn/google/play/billing/billing_testing.html",
-      "intl/zh-cn/google/play/billing/billing_best_practices.html"
-    ]
-  },
-  "overview/zhcn/3": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-
-      "intl/zh-cn/distribute/tools/promote/device-art.html",
-      "intl/zh-cn/distribute/tools/promote/linking.html",
-      "intl/zh-cn/distribute/tools/promote/brand.html",
-      "intl/zh-cn/tools/help/proguard.html"
-    ]
-  },
-  "overview/zhcn/4": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/design/style/writing.html",
-      "intl/zh-cn/training/basics/fragments/fragment-ui.html",
-      "intl/zh-cn/training/multiscreen/index.html",
-      "intl/zh-cn/training/monitoring-device-state/index.html"
-    ]
-  },
-  "overview/carousel/zhcn": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=vGV7FHGzpFU",
-      "https://www.youtube.com/watch?v=aqc3ZOTzpdk",
-      "https://www.youtube.com/watch?v=jaNrJ8uyLSc"
-    ]
-  },
-  "overview/1": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/quality/core.html",
-      "distribute/essentials/quality/tablets.html",
-      "distribute/tools/launch-checklist.html",
-      "tools/publishing/publishing_overview.html",
-      "distribute/tools/localization-checklist.html"
-    ]
-  },
-    "overview/2": {
-    "title": "",
-    "resources": [
-      "google/play/billing/index.html",
-      "google/play/billing/api.html",
-      "google/play/billing/billing_admin.html",
-      "google/play/billing/billing_testing.html",
-      "google/play/billing/billing_best_practices.html"
-    ]
-  },
-  "overview/3": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/device-art.html",
-      "distribute/tools/promote/linking.html",
-      "distribute/tools/promote/brand.html",
-      "tools/help/proguard.html"
-    ]
-  },
-  "overview/4": {
-    "title": "",
-    "resources": [
-      "design/style/writing.html",
-      "training/basics/fragments/fragment-ui.html",
-      "training/multiscreen/index.html",
-      "training/monitoring-device-state/index.html"
-    ]
-  },
-"tools/help/log": {
-    "title": "",
-    "resources": [
-       "tools/help/am-logcat.html"
-    ]
-  },
-"tools/help/monitor": {
-    "title": "",
-    "resources": [
-       "tools/help/am-memory.html",
-       "tools/help/am-cpu.html",
-       "tools/help/am-gpu.html",
-       "tools/help/am-network.html"
-    ]
-  },
- "tools/help/data": {
-    "title": "",
-    "resources": [
-       "tools/help/am-hprof.html",
-       "tools/help/am-allocation.html",
-       "tools/help/am-methodtrace.html",
-       "tools/help/am-sysinfo.html"
-    ]
-  },
-  "tools/help/shot": {
-    "title": "",
-    "resources": [
-       "tools/help/am-screenshot.html",
-       "tools/help/am-video.html"
-    ]
-  },
-  "tools/performance/rendering": {
-    "title": "",
-    "resources": [
-       "tools/performance/debug-gpu-overdraw/index.html",
-       "tools/performance/profile-gpu-rendering/index.html",
-       "tools/performance/hierarchy-viewer/setup.html",
-       "tools/performance/hierarchy-viewer/index.html",
-       "tools/performance/hierarchy-viewer/profiling.html"
-    ]
-  },
-  "tools/performance/memory": {
-    "title": "",
-    "resources": [
-       "tools/performance/memory-monitor/index.html",
-       "tools/performance/heap-viewer/index.html",
-       "tools/performance/allocation-tracker/index.html",
-       "tools/performance/comparison.html"
-    ]
-  },
-  "tools/performance/cpu": {
-    "title": "",
-    "resources": [
-       "tools/performance/traceview/index.html",
-       "tools/performance/systrace/index.html"
-    ]
-  },
-  "tools/performance/battery": {
-    "title": "",
-    "resources": [
-       "tools/performance/batterystats-battery-historian/index.html",
-       "tools/performance/batterystats-battery-historian/charts.html"
-    ]
-  },
-  "marshmallow/landing/resources": {
-    "title": "",
-    "resources": [
-       "about/versions/marshmallow/android-6.0-changes.html",
-       "about/versions/marshmallow/android-6.0.html",
-       "about/versions/marshmallow/samples.html"
-    ]
-  },
-  "marshmallow/landing/videos": {
-    "title": "",
-    "resources": [
-       "https://youtu.be/U9tw5ypqEN0",
-       "https://youtu.be/N72ksDKrX6c",
-       "https://youtu.be/iZqDdvhTZj0",
-       "https://www.youtube.com/watch?v=vcSj8ln-BlE",
-       "https://youtu.be/LQoohRwojmw",
-       "https://www.youtube.com/watch?v=VOn7VrTRlA4",
-       "https://youtu.be/5sCQjeGoE7M",
-       "https://www.youtube.com/watch?v=C8lUdPVSzDk",
-       "https://www.youtube.com/watch?v=HXacyy0HSW0",
-       "https://www.youtube.com/watch?v=OW1A4XFRuyc",
-       "https://www.youtube.com/watch?v=j3QC6hcpy90",
-       "https://www.youtube.com/watch?v=f17qe9vZ8RM",
-       "https://www.youtube.com/watch?v=ndBdf1_oOGA"
-    ]
-  },
-  "marshmallow/landing/more": {
-    "title": "",
-    "resources": [
-      "training/permissions/requesting.html",
-      "training/backup/autosyncapi.html",
-      "training/monitoring-device-state/doze-standby.html",
-      "training/app-links/index.html",
-      "training/articles/assistant.html",
-      "training/testing/performance.html",
-      "https://developers.google.com/android/nexus/images"
-    ]
-  },
-  "tools/landing/resources": {
-    "title": "",
-    "resources": [
-    "tools/studio/index.html",
-    "tools/studio/studio-features.html",
-    "studio/intro/index.html",
-    ]
-  },
-  "tools/landing/latest": {
-    "title": "",
-    "resources": [
-    "https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
-    "http://android-developers.blogspot.com/2016/04/android-studio-2-0.html",
-    "https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
-    ]
-  },
-  "work/landing/primary": {
-    "title": "",
-    "resources": [
-      "work/overview.html",
-      "work/guide.html",
-      "https://www.google.com/work/android/developers/applyDevHub/",
-      "work/managed-configurations.html",
-      "work/cosu.html",
-      "work/managed-profiles.html"
-    ]
-  },
-  "work/landing/resources": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/android/work/",
-      "https://www.google.com/work/android/",
-      "https://developers.google.com/android/work/build-dpc",
-      "https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-      "https://www.youtube.com/watch?v=Za0OQo8DRM4",
-      "https://www.youtube.com/watch?v=dH41OutAMNM&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX"
-    ]
-  },
-  "work/apps": {
-    "title": "",
-    "resources": [
-      "work/managed-profiles.html",
-      "work/managed-configurations.html",
-      "work/cosu.html",
-      "https://www.youtube.com/watch?v=39NkpWkaH8M&index=2&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-      "samples/AppRestrictionSchema/index.html",
-      "samples/AppRestrictionEnforcer/index.html"
-    ]
-  },
-  "work/admin": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/android/work/build-dpc",
-      "samples/BasicManagedProfile/index.html",
-      "https://www.youtube.com/watch?v=j3QC6hcpy90"
-    ]
-  }
-};
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
deleted file mode 100644
index 44ccafa..0000000
--- a/docs/html/jd_extras.js
+++ /dev/null
@@ -1,4120 +0,0 @@
-/*
- * THIS FILE IS DEPRECATED.
- *
- * Please add and edit resource collections in jd_extras_<lang>.js
- * where lang matches the language code appropriate for the resource.
- * Last sync'd with jd_extras_<lang>.js on 29 Apr 2016.
- *
- */
-DISTRIBUTE_RESOURCES = DISTRIBUTE_RESOURCES.concat([
- /* TODO Remove standard resources from here, such as below
- */
-  {
-    "title":"Writing More Code by Writing Less Code with Android Studio Live Templates",
-    "titleFriendly":"",
-    "summary":"Unless you’re getting paid by the keystroke, no one wants to write repetitive boilerplate code.",
-    "url":"https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
-    "group":"",
-    "keywords": [],
-    "tags": ['studio'],
-    "image":"https://cdn-images-1.medium.com/max/800/1*JkrYXGs1AxZAbK0sCLrJAQ.gif",
-    "type":"medium"
-  },
-  {
-    "title":"How Often Should You Update Android Studio?",
-    "titleFriendly":"",
-    "summary":"One of the beauties of Android Studio is how quickly is evolves and improves.",
-    "url":"https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
-    "group":"",
-    "keywords": [],
-    "tags": ['studio'],
-    "image":"https://cdn-images-1.medium.com/max/2000/1*chMiA9mGa_FBUOoesHHk3Q.png",
-    "type":"medium"
-  },
-  {
-    "title":"SmallerAPK, Part 6: Image optimization, Zopfli & WebP",
-    "category":"",
-    "summary":"Series of posts on minimizing your APK size.",
-    "url":"https://medium.com/@wkalicinski/smallerapk-part-6-image-optimization-zopfli-webp-4c462955647d#.23hlddo3x",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"https://cdn-images-1.medium.com/max/2000/1*chMiA9mGa_FBUOoesHHk3Q.png",
-    "type":"medium"
-  },
-  {
-    "title":"Measure your app’s user acquisition channels",
-    "titleFriendly":"",
-    "summary":"Get details on how to use the Developer Console User Acquisitions reports to discover where your users come from.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/6263332",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Set up native app install banners in Chrome",
-    "titleFriendly":"",
-    "summary":"Get the details you need to add your native app or game to your site’s web app manifest file.",
-    "url":"https://developers.google.com/web/updates/2015/03/increasing-engagement-with-app-install-banners-in-chrome-for-android#native",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Optimize your store listing pages with experiments",
-    "titleFriendly":"",
-    "summary":"You can run experiments to find the most effective graphics and localized text for your app.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/6227309",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Content Experiments for Mobile Apps",
-    "titleFriendly":"",
-    "summary":"Google Analytics Content Experiments allows you to test multiple variations of a given web page.",
-    "url":"https://support.google.com/tagmanager/answer/6003007",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Store Listing Experiments for Google Play",
-    "titleFriendly":"",
-    "summary":"Learn how to use Google Play’s new store listing optimization feature to get more installs of your app.",
-    "url":"https://www.youtube.com/watch?v=B6ydLpkhq04",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/B6ydLpkhq04/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Use alpha/beta testing & staged rollouts",
-    "titleFriendly":"",
-    "summary":"Using the Google Play Developer Console, you can choose groups of users to test different versions of your app.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/3131213",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Quizlet Developer Story",
-    "titleFriendly":"",
-    "summary":"Quizlet is an extremely popular online learning tool for students. See how they optimized for the classroom with Android and the power of Google Play for Education.",
-    "url":"https://www.youtube.com/watch?v=Idu7VcTTXfk",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/Idu7VcTTXfk/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"What's New in GPFE",
-    "titleFriendly":"",
-    "summary":"Learn about the vision and philosophy behind Google Play for Education",
-    "url":"https://www.youtube.com/watch?v=IKhU180eJMo",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/IKhU180eJMo/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Get started with Google Cast",
-    "titleFriendly":"",
-    "summary":"Build multi-screen experiences, let the user send video and audio content to TVs and speakers.",
-    "url":"https://developers.google.com/cast/docs/ux_guidelines",
-    "group":"",
-    "keywords": ["cast", "chromecast", "video", "audio"],
-    "tags": [],
-    "image":"images/cards/card-cast_2x.jpg",
-    "type":"Guide"
-  },
-  {
-    "title":"Android Sender Applications",
-    "titleFriendly":"",
-    "summary":"Get an overview of how your Android app can act as a Google Cast sender app.",
-    "url":"https://developers.google.com/cast/docs/android_sender",
-    "group":"",
-    "keywords": ["cast", "sender"],
-    "tags": [],
-    "image":"images/cards/card-cast_2x.jpg",
-    "type":"Guide"
-  },
-  {
-    "title":"Cast sample apps",
-    "titleFriendly":"",
-    "summary":"Get example Google Cast applications for both senders and receivers.",
-    "url":"https://www.github.com/googlecast",
-    "group":"",
-    "keywords": ["cast", "samples"],
-    "tags": [],
-    "image":"images/cards/card-cast_2x.jpg",
-    "type":"Samples"
-  },
-  {
-    "title":"Get Cardboard",
-    "titleFriendly":"",
-    "summary":"Get your own Cardboard, today. Buy one from a manufacturer or build your own, and start developing.",
-    "url":"https://www.google.com/get/cardboard/get-cardboard/",
-    "group":"",
-    "keywords": ["carboard","vr"],
-    "tags": [],
-    "image":"images/cards/card-cardboard_2x.png",
-    "type":"Guide"
-  },
-    {
-    "title":"Download the Cardboard SDK",
-    "titleFriendly":"",
-    "summary":"Grab the Cardboard libraries from GitHub and start creating VR apps in your favorite development environment.",
-    "url":"https://developers.google.com/cardboard/android/download",
-    "group":"",
-    "keywords": ["carboard","vr"],
-    "tags": [],
-    "image":"images/cards/card-cardboard_2x.png",
-    "type":"Guide"
-  },
-  {
-    "title":"Cardboard design guidelines",
-    "titleFriendly":"",
-    "summary":"Focus on overall usability and avoiding common VR pitfalls while creating an immersive experience of your own.",
-    "url":"https://www.google.com/design/spec-vr",
-    "group":"",
-    "keywords": ["carboard","vr"],
-    "tags": [],
-    "image":"images/cards/card-cardboard_2x.png",
-    "type":"Design"
-  },
-  {
-    "title":"Maps",
-    "titleFriendly":"",
-    "summary":"Give users the map that more than a billion people use every month.",
-    "url":"https://developers.google.com/maps/documentation/android/",
-    "group":"",
-    "keywords": ["maps"],
-    "tags": [],
-    "image":"images/google/gps-maps.png",
-    "type":"Guide"
-  },
-    {
-    "title":"Places API",
-    "titleFriendly":"",
-    "summary":"give your users contextual information about where they are, when they’re there.",
-    "url":"https://developers.google.com/places/android/",
-    "group":"",
-    "keywords": ["places","location", "context"],
-    "tags": [],
-    "image":"images/cards/card-places_2x.png",
-    "type":"Guide"
-  },
-  {
-    "title":"GCM Client for Android",
-    "titleFriendly":"",
-    "summary":"Send push notifications and pubsub from your server to Android devices around the world.",
-    "url":"https://developers.google.com/cloud-messaging/android/client",
-    "group":"",
-    "keywords": ["push","gcm"],
-    "tags": [],
-    "image":"images/cards/card-google-cloud-messaging_16-9_2x.png",
-    "type":"Guide"
-  },
-  {
-    "title":"Google Cloud Messaging",
-    "titleFriendly":"",
-    "summary":"Learn about GCM and the kinds of services you can offer to users through push notifications",
-    "url":"https://developers.google.com/cloud-messaging/gcm",
-    "group":"",
-    "keywords": ["push","gcm"],
-    "tags": [],
-    "image":"images/cards/card-google-cloud-messaging_16-9_2x.png",
-    "type":"Guide"
-  },
-  {
-    "title":"ClassDojo Developer Story",
-    "titleFriendly":"",
-    "summary":"ClassDojo is a classroom tool that helps teachers improve behavior in their classrooms quickly and easily. See how they optimized for the classroom with Android and the power of Google Play for Education.",
-    "url":"https://www.youtube.com/watch?v=iokH4SAIfRw",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/iokH4SAIfRw/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Plan for Success",
-    "titleFriendly":"",
-    "summary":"5 tips from developers on creating great EDU apps.",
-    "url":"https://www.youtube.com/watch?v=Eh2adsAyTKc",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/Eh2adsAyTKc/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Optimizing Apps for Education",
-    "titleFriendly":"",
-    "summary":"Learn how to optimize your app for teachers and students.",
-    "url":"https://www.youtube.com/watch?v=_AZ6UcPz-_g",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/_AZ6UcPz-_g/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Ideas and Tools for Building Innovative Education Apps",
-    "titleFriendly":"",
-    "summary":"Are you hungry to build an awesome app for education but don't quite know where to start? Come hear about apps that teachers want, and the APIs you're going to need to build them! In particular, we'll talk about app ideas that combine APIs for Google Drive, Google Login, Android Single Task Mode and more to build transformative Educational apps that will delight educators and kids in and out of the classroom.",
-    "url":"https://www.youtube.com/watch?v=iulXz8QTD1g",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/iulXz8QTD1g/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"DesignBytes: Intro To Material Design",
-    "titleFriendly":"",
-    "summary":"These days, UI designers need to be thinking about phones, tablets, laptops, TVs, smartwatches, and beyond. In this DesignByte we talk about how Google designers have been working on making cross-platform and multi-screen design easier. We wanted to build a design system that felt at home on every screen, from the smallest watch to the largest TV.",
-    "url":"https://www.youtube.com/watch?v=p4gmvHyuZzw",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/p4gmvHyuZzw/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"DesignBytes: Paper and Ink: The Materials that Matter",
-    "titleFriendly":"",
-    "summary":"Join Rich Fulcher to learn about the materials of material design. See how virtual paper and ink form the foundation of your tactile user interface and master the rules that govern their behaviour.",
-    "url":"https://www.youtube.com/watch?v=YaG_ljfzeUw",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/YaG_ljfzeUw/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"DesignBytes: Material Design in the Google I/O App",
-    "titleFriendly":"",
-    "summary":"Roman Nurik shares details on the design process for the Google I/O 2014 app. To check out the app's source code, visit github.com/google/iosched.",
-    "url":"https://www.youtube.com/watch?v=XOcCOBe8PTc",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/XOcCOBe8PTc/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Toolbars for a flexible Action Bar & more",
-    "titleFriendly":"",
-    "summary":"Toolbars are a flexible View you can add to your Android app which provides many of the same APIs as the system provided Action Bar, but can also do so much more such as reacting to scrolling or being integrated directly into your layouts.",
-    "url":"https://www.youtube.com/watch?v=kmUGLURRPkI",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/kmUGLURRPkI/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Protecting Implicit Intents with Runtime Checks",
-    "titleFriendly":"",
-    "summary":"Make sure you protect your implicit intents with a simple runtime check.",
-    "url":"https://www.youtube.com/watch?v=HGElAW224dE",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/HGElAW224dE/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Tabs and ViewPager",
-    "titleFriendly":"",
-    "summary":"Showing multiple screens or pages of content is easy with the help of ViewPager and a PagerAdapter. Combining that with tabs make for an effective top level navigation strategy for your app or for moving between content at the same level of hierarchy within your app.",
-    "url":"https://www.youtube.com/watch?v=zQekzaAgIlQ",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/zQekzaAgIlQ/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Battery Drain and Networking",
-    "titleFriendly":"",
-    "summary":"Let’s take a moment to make something insanely clear: As far as battery is concerned, NETWORKING is the biggest, baddest, dirtiest offender there is. And optimizing performance here isn’t easy. Since the chip isn’t always awake and draining power, means you can optimize how it wakes up, sends traffic, and saves battery.",
-    "url":"https://www.youtube.com/watch?v=fEEulSk1kNY",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/fEEulSk1kNY/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Batching Background Work Until Later",
-    "titleFriendly":"",
-    "summary":"Yes, your app is special. But when it comes to battery use, sometimes it’s better to be part of the crowd. Why not spread the battery blame around a bit? Ian Ni-Lewis shows you how ridiculously easy it is to go from battery hog to team player in this video.",
-    "url":"https://www.youtube.com/watch?v=-3ry8PxcJJA",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/-3ry8PxcJJA/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"The Performance Lifecycle",
-    "titleFriendly":"",
-    "summary":"Performance problems surface in your application at the least-wanted times (like right before you’re about to ship your first build). But don’t freak out: There’s a simple process that you can follow to help get your performance back under control.",
-    "url":"https://www.youtube.com/watch?v=_kKTGK-Cb_4",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/_kKTGK-Cb_4/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Introduction to Android Studio",
-    "titleFriendly":"",
-    "summary":"Learn why you should migrate your projects to Android Studio now and how it can help you be more productive as a developer. Rich layout editor, handy suggestions and fixes, new Android project view - these are just some of the things you can expect from the IDE, which is built on the successful IntelliJ IDEA.",
-    "url":"https://www.youtube.com/watch?v=K2dodTXARqc&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-    "group":"",
-    "keywords": ["studio", "tools"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/K2dodTXARqc/maxresdefault.jpg",
-    "type":"video"
-  },
-
-  {
-    "title":"Google Play Services 7.5",
-    "titleFriendly":"",
-    "summary":"This update brings App Invites, topics to GCM, GCMNetworkManager, Cast Remote Display API, Smart Lock for Passwords, Maps API for Android Wear, Google Fit extensions and more.",
-    "url":"https://www.youtube.com/watch?v=M3Udfu6qidk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-    "group":"",
-    "keywords": ["google play services"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/M3Udfu6qidk/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Google Play Services 7.3",
-    "titleFriendly":"",
-    "summary":"This update brings the ability to connect multiple wearables simultaneously to a single phone. There are also some great new updates to Google Fit, including nutrition types, and to Location.",
-    "url":"https://www.youtube.com/watch?v=FOn64iqlphk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-    "group":"",
-    "keywords": ["google play services"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/FOn64iqlphk/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Google Play Services 6.5",
-    "titleFriendly":"",
-    "summary":"Google Play services 6.5 includes new features in Google Maps, Google Drive and Google Wallet as well as the recently launched Google Fit API. ",
-    "url":"https://www.youtube.com/watch?v=fvtMtfCuEpw&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-    "group":"",
-    "keywords": ["google play services"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/fvtMtfCuEpw/maxresdefault.jpg",
-    "type":"video"
-  },
-    {
-    "title":"Google Play Services 7.0",
-    "titleFriendly":"",
-    "summary":"Google Play services 7.0 is here! we've added the Places API, made enhancements to Location and Google Fit, and you can also remote control your Android TV through the new Nearby Connections API.",
-    "url":"https://www.youtube.com/watch?v=F0Kh_RnSM0w&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-    "group":"",
-    "keywords": ["google play services"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/F0Kh_RnSM0w/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Running a Successful Games Business with Google",
-    "titleFriendly":"",
-    "summary":"Sure, we all want to make the next great gaming masterpiece. But we also want to feed our families and/or dogs. Join Bob Meese from the Google Play team as he gives you some key pointers on how to make sure you're best taking advantage of Google Play and running a successful games business.",
-    "url":"https://www.youtube.com/watch?v=tDmnGNkTtlE",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/tDmnGNkTtlE/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Introduction to Android TV",
-    "titleFriendly":"",
-    "summary":"Android TV brings the Android platform to the living room with rich content and entertaining app experiences. In this video, Timothy introduces the design philosophy and developer components that make building TV experiences easier than ever before.",
-    "url":"https://www.youtube.com/watch?v=6K_jxccHv5M&index=1&list=PLOU2XLYxmsILFBfx66ens76VMLMEPJAB0",
-    "group":"",
-    "keywords": ["tv"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/6K_jxccHv5M/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Introduction to Android Auto",
-    "titleFriendly":"",
-    "summary":"Android Auto brings the Android platform to the car in a way that's optimized for the driving experience. It's the same platform you already use for phones, tablets, televisions, wearables, and more. ",
-    "url":"https://www.youtube.com/watch?v=ctiaVxgclsg&list=PLWz5rJ2EKKc9BdE_PSLNIGjXXr3h_orXM",
-    "group":"",
-    "keywords": ["auto"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/ctiaVxgclsg/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Debugging and testing in Android Studio",
-    "titleFriendly":"",
-    "summary":"This video introduces the state of unit testing support in Studio and Google’s new Android Testing Support Library for functional UI testing and running instrumented tests on a device.",
-    "url":"https://www.youtube.com/watch?v=2I6fuD20qlY",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/2I6fuD20qlY/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Android Testing (Android Dev Summit 2015)",
-    "titleFriendly":"",
-    "summary":"Overview of the testing tools and frameworks provided by Google and how they can help you to iterate more quickly and maintain a more healthy codebase.",
-    "url":"https://www.youtube.com/watch?v=vdasFFfXKOY",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/vdasFFfXKOY/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"dumpsys",
-    "titleFriendly":"",
-    "summary":"A tool that runs on the device and provides information about the status of system services.",
-    "url":"https://source.android.com/devices/tech/debug/dumpsys.html",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"",
-    "type":"google"
-  },
-  {
-    "title":"Android Testing Samples",
-    "titleFriendly":"",
-    "summary":"A collection of samples demonstrating different frameworks and techniques for automated testing.",
-    "url":"https://github.com/googlesamples/android-testing",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"images/testing/testing-icon.png",
-    "type":"Samples"
-  },
-  {
-    "title":"Android Testing Templates",
-    "titleFriendly":"",
-    "summary":"A collection of Google's Android testing tools and frameworks, all integrated in a single application project.",
-    "url":"https://github.com/googlesamples/android-testing-templates",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"images/testing/testing-icon.png",
-    "type":"Samples"
-  },
-   {
-    "title":"Android Testing Support Library (GitHub)",
-    "titleFriendly":"",
-    "summary":"A resource page on GitHub for the Android Testing Support Library.",
-    "url":"https://google.github.io/android-testing-support-library",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"images/testing/testing-icon.png",
-    "type":"Samples"
-  },
-  {
-    "title":"Android Testing Codelab",
-    "titleFriendly":"",
-    "summary":"This codelab shows how to build an Android app from the ground up in Android Studio, using a Model View Presenter architecture, Unit Tests and Instrumentation Tests.",
-    "url":"https://codelabs.developers.google.com/codelabs/android-testing/index.html",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"images/testing/testing-icon.png",
-    "type":"google"
-  },
-  {
-    "title":"Developer Registration",
-    "titleFriendly":"",
-    "summary":"Additional information about the registration process.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/113468",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title": "Google Play Distribution and Seller Countries",
-    "titleFriendly":"",
-    "summary": "List of countries and territories where you can distribute your apps in Google Play.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/138294",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title": "支持向Google Play用户发布应用的地区",
-    "lang": "zh-cn",
-    "titleFriendly":"",
-    "summary": "支持向Google Play用户发布应用的国家/地区。",
-    "url":"https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Google Play Content Policies",
-    "titleFriendly":"",
-    "summary":"Details on policies relating to your developer account and app distribution is governed.",
-    "url":"https://support.google.com/googleplay/android-developer/topic/3453577",
-    "group":"",
-    "keywords": [],
-    "tags": ["#developersupport"],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Google Play Badge Generator",
-    "titleFriendly":"",
-    "summary":"Build badges for your app in just a few clicks, or download hi-res badge assets localized for a variety of languages.",
-    "url":"https://play.google.com/intl/en_us/badges/",
-    "group":"",
-    "keywords": [],
-    "tags": ["#developersupport"],
-    "image":"images/gp-badges-set.png",
-    "type":"google"
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["#developersupport #termsandpolicies"],
-    "url": "https://support.google.com/googleplay/android-developer/answer/4407611",
-    "timestamp": 1194884220000,
-    "image": 'images/play_dev.jpg',
-    "title": "Google Play Terms and Policies",
-    "summary": "Developer terms and policies that apply when you distribute apps in Google Play.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "title":"Google Play Policy Center",
-    "titleFriendly":"",
-    "summary":"A central resource for you to learn about Google Play policies and guidelines.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/4430948",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
-    "type":"google"
-  },
-  {
-    "title":"Google Play应用政策中心",
-    "titleFriendly":"",
-    "summary":"一个方便你了解Google Play政策和指南的中心资源。",
-    "url":"https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
-    "type":"google"
-  },
-  {
-    "title":"Developer Help Center",
-    "titleFriendly":"",
-    "summary":"Complete details on getting started, publishing, troubleshooting, and more.",
-    "url":"https://support.google.com/googleplay/android-developer",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/cards/google-play_2x.png",
-    "type":"google"
-  },
-  {
-    "title":"开发者帮助中心",
-    "titleFriendly":"",
-    "summary":"完整资料帮助开发者新手入手,发布,故障排除,等等",
-    "url":"https://support.google.com/googleplay/android-developer?hl=zh-Hans",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Google for Education",
-    "titleFriendly":"",
-    "summary":"Find out more about how Google can support your work with apps and tablets.",
-    "url":"https://www.google.com/edu/tablets/",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"distribute/images/gp-edu-apps-image.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Keeping Your App Responsive",
-    "titleFriendly":"",
-    "summary":"This document describes how the Android system determines whether an application is not responding and provides guidelines for ensuring that your application stays responsive.",
-    "url":"training/articles/perf-anr.html",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"",
-    "type":"google"
-  },
-  {
-    "title":"Google Play Game Services",
-    "titleFriendly":"",
-    "summary":"Make your games social with Google Play game services. Add achievements, leaderboards, real-time multiplayer, and other popular features using the Google Play game services SDK.",
-    "url":"https://developers.google.com/games/services/",
-    "group":"",
-    "keywords": ["games","play games"],
-    "tags": [],
-    "image":"images/google/gps-play_games_logo.png",
-    "type":"google"
-  },
-  {
-    "title":"Get Started with Analytics",
-    "titleFriendly":"",
-    "summary":"Get advanced insight into how players discover and play your games.",
-    "url":"distribute/analyze/start.html",
-    "group":"",
-    "keywords": ["analytics"],
-    "tags": [],
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "type": "distribute"
-  },
-  {
-    "title":"Build VR with Google Cardboard",
-    "titleFriendly":"",
-    "summary":"Turn any phone into a virtual reality headset with a Cardboard viewer and experiment with adding virtual reality to your games with the Cardboard SDK.",
-    "url":"distribute/googleplay/cardboard.html",
-    "group":"",
-    "keywords": ["cardboard"],
-    "tags": [],
-    "image":"images/cards/card-cardboard_2x.png",
-    "type": "distribute"
-  },
-  {
-    "title":"Monetize your apps intelligently",
-    "titleFriendly":"",
-    "summary":"Generate revenue from your free games with ads tailored to match your game's look and feel.",
-    "url":"https://www.google.com/admob/",
-    "group":"",
-    "keywords": ["AdMob"],
-    "tags": [],
-    "image":"images/cards/admob-analytics_2x.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "versions", "blog", "googleplay"
-    ],
-    "url": "https://android-developers.blogspot.com/",
-    "timestamp": 1004884220000,
-    "image": "images/blog.jpg",
-    "title": "Android Developers Blog",
-    "summary": "Follow the latest news on Android design, development, and distribution.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Making Android Apps that Play Nice",
-    "summary": "Audio lifecycle and expected audio behaviors for Android apps.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://android-developers.blogspot.com/2010/07/multithreading-for-performance.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Multithreading for Performance",
-    "summary": "Ways to improve performance through multi-threading.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://play.google.com/about/developer-content-policy.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Developer Program Policies",
-    "summary": "Guidelines acceptable content in Google Play. Please read and understand the policies before publishing.",
-    "keywords": [],
-    "type": "google",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/188189",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Rating your application content for Google Play",
-    "summary": "How to choose the appropriate content ratings level for your apps.",
-    "keywords": [],
-    "type": "support",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["devices", "nexus", "testing"],
-    "url": "https://developers.google.com/android/nexus/images",
-    "timestamp": 1194884220000,
-    "image": "images/cards/card-download_16-9_2x.png",
-    "title": "Factory Images for Nexus Devices",
-    "summary": "System image files for Android 6.0 and other Android releases.",
-    "keywords": ["nexus, downloads"],
-    "type": "support",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "针对Google Play为你的应用内容分级",
-    "summary": "如何为你的应用内容分级。",
-    "keywords": [],
-    "type": "support",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Google Play Featured Image Guidelines",
-    "summary": "How to create attractive, effective Featured Images for your apps.",
-    "keywords": [],
-    "type": "support",
-    "titleFriendly": ""
-  },
-{
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113477",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Supporting your users",
-    "summary": "Options for supporting users.",
-    "keywords": [],
-    "type": "support",
-    "titleFriendly": ""
-  },
-{
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "为用户提供支持",
-    "summary": "为用户提供支持的各种选择。",
-    "keywords": [],
-    "type": "support",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/practices/screens_support.html#ConfigurationExamples",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Configuration examples",
-    "summary": "How to declare layouts and other resources for specific screen sizes.",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "training/design-navigation/multiple-sizes.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Planning for Multiple Touchscreen Sizes",
-    "summary": "",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "training/multiscreen/index.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Designing for Multiple Screens",
-    "summary": "Designing an intuitive, effective navigation for tablets and other devices.",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/resources/providing-resources.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Providing Resources",
-    "summary": "Layouts and drawable resources for specific ranges of device screens.",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "training/basics/supporting-devices/screens.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Supporting Different Screens",
-    "summary": "Optimizing the user experience for different screen sizes and densities.",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/appwidgets/index.html#MetaData",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Adding the AppWidgetProviderInfo Metadata",
-    "summary": "How to set the height and width dimensions of a widget.",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Android API Levels",
-    "summary": "Introduction to API levels and how they relate to compatibility.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Declaring screen size support",
-    "summary": "How to declare support for screen sizes in your app\'s manifest.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "training/material/animations.html#Touch",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Customize Touch Feedback",
-    "summary": "Provide visual confirmation when users interact with your UI.",
-    "keywords": [],
-    "type": "develop",
-    "category": "guide"
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/manifest/uses-feature-element.html#testing",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Checking for hardware feature requirements",
-    "summary": "Determining an app’s hardware and software requirements.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://play.google.com/apps/publish/",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Google Play Developer Console",
-    "summary": "The tools console for publishing your app.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://play.google.com/apps/publish/?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Google Play 开发者控制台",
-    "summary": "发布应用的开发者控制台",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://youtu.be/SkHHPf3EdzE",
-    "timestamp": 1194884220000,
-    "image": "https://i1.ytimg.com/vi/SkHHPf3EdzE/maxresdefault.jpg",
-    "title": "Level Up Your Android Game",
-    "summary": "Learn how to take your game to the next level on Google Play.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
-    "timestamp": 1194884220000,
-    "image": 'images/google/gps-googleplus.png',
-    "title": "Sharing interactive posts to Google+ from your Android app",
-    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
-    "keywords": ["Interactive", "Google+"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://play.google.com/about/developer-distribution-agreement.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Developer Distribution Agreement",
-    "summary": "Terms for distributing and selling apps and in-app products in Google Play.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113417",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Inappropriate content in comments and applications",
-    "summary": "More details on what content is appropriate.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/legal/troubleshooter/1114905",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Removing content from Google",
-    "summary": "Find how how to request the removal of content that infringes on your trademark.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://play.google.com/about/developer-distribution-agreement-addendum.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Google Play for Education Addendum",
-    "summary": "Review the education-specific requirements.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
-    "timestamp": null,
-    "image": null,
-    "title": "Native RTL Support in Android 4.2",
-    "summary": "Blog post that explains how to support RTL in your UI.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/resources/string-resource.html#Plurals",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Quantity Strings (Plurals)",
-    "summary": "How to work with string plurals according to rules of grammar in a given locale.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "reference/java/util/Locale.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Locale",
-    "summary": "Determine what CLDR data or version of the Unicode spec a particular Android platform version uses.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-    {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/resources/string-resource.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "String Resources",
-    "summary": "Explains how to use string resources in your UI.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "distribute/tools/localization-checklist.html#strings",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Manage strings for localization",
-    "summary": "Guidance on having your strings translation ready.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "tools/publishing/publishing_overview.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "General Publishing Overview",
-    "summary": "Start here for an overview of publishing options for Android apps.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "tools/publishing/preparing.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Preparing for Release",
-    "summary": "Developer documentation on how to build the signed, release-ready APK. This process is the same for all Android apps.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "distribute/googleplay/policies/index.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Google Play Policies and Guidelines",
-    "summary": "An overview of Google Play policies for spam, intellectual property, and ads, with examples of common problems.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/topic/2364761",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Policy and Best Practices",
-    "summary": "Help Center document describing various content policies and processes.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/topic/2364761?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "政策和最佳做法",
-    "summary": "内容政策和流程",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "google/play/expansion-files.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "APK Expansion Files",
-    "summary": "Developer documentation describing APK Expansion Files and how to support them in your app.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "tools/help/proguard.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "ProGuard",
-    "summary": "Developer documentation describing how to use ProGuard to shrink, optimize, and obfuscate your code prior to release.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "title":"Dashboards",
-    "titleFriendly":"",
-    "summary":"This page provides information about the relative number of devices that share a certain characteristic, such as Android version or screen size. This information may help you prioritize efforts for supporting different devices by revealing which devices…",
-    "url":"about/dashboards/index.html",
-    "group":"",
-    "keywords": ["android","dashboard","platforms","versions"],
-    "tags": ["#ecosystem","#versions","#whatsnew"],
-    "image":"https://chart.googleapis.com/chart?chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A0.1%2C93.5%2C6.4&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
-    "lang":"en",
-    "type":"about"
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/wallet/instant-buy/",
-    "timestamp": 1194884220000,
-    "image": "",
-    "title": "Android Pay APIs",
-    "summary": "Developer documentation describing Instant Buy and how to support it in your apps.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1169947",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Selling Apps in Multiple Currencies",
-    "summary": "Help Center document describing how pricing works in Google Play.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1169947?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "以多种货币销售应用",
-    "summary": "如何在Google Play为应用定价",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/138412",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Prices and supported currencies",
-    "summary": "Help Center document listing supported currencies for pricing your apps.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-    {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/138412?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "各国家/地区获许定价范围和货币",
-    "summary": "各国家/地区获许定价范围和货币列表",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/112622",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Transaction Fees",
-    "summary": "Help Center document describing transaction fees for priced apps and in-app products.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/112622?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "交易费用",
-    "summary": "销售的应用和应用内产品的交易费。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/138000",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Specifying tax rates",
-    "summary": "Help Center document describing how to set tax rates for different countries.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/138000?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "税率",
-    "summary": "如何设置不同国家/地区的税率",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/resources/localization.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Localizing with Resources",
-    "summary": "Developer guide to localizing resources in your app.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113475",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Category types",
-    "summary": "Help Center document listing available categories for apps.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113475?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "类别",
-    "summary": "应用的类别列表。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113476",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Updates",
-    "summary": "Requirements for app updates in Google Play.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113476?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "更新应用",
-    "summary": "更新Google Play应用的要求。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1153479",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "In-app Billing",
-    "summary": "Help Center document describing how to correctly set up In-app Billing.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1153479?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "应用内结算",
-    "summary": "如何正确设置应用内商品和订阅结算。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "url": "https://youtu.be/vzvpcEffvaE",
-    "timestamp": 1383243492000,
-    "image": "https://i1.ytimg.com/vi/vzvpcEffvaE/maxresdefault.jpg",
-    "title": "Introducing Tablets with Google Play for Education",
-    "summary": "Schools in Hillsborough, New Jersey were among the first to try out Nexus 7 tablets with Google Play for Education. See the difference it made for students, teachers, and administrators.",
-    "keywords": [],
-    "type": "video",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#engagement",
-    ],
-    "url": "https://www.youtube.com/yt/dev/",
-    "timestamp": 1383243492000,
-    "image": "https://www.youtube.com/yt/dev/media/images/yt-dev-home-hero.jpg",
-    "title": "YouTube for Developers",
-    "summary": "The YouTube APIs and Tools enable you to integrate YouTube's video content and functionality into your website, app, or device.",
-    "keywords": [],
-    "type": "youtube",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#engagement",
-    ],
-    "url": "https://www.google.com/analytics/mobile/",
-    "timestamp": 1383243492000,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Mobile App Analytics",
-    "summary": "Mobile App Analytics measures what matters most at all key stages: from first discovery and download to in-app purchases. ",
-    "keywords": ["analytics,user behavior"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-
-
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#gcm",
-    ],
-    "url": "https://www.youtube.com/watch?v=y76rjidm8cU",
-    "timestamp": 1383243492000,
-    "image": "https://1.bp.blogspot.com/-IF-1-1kA0sg/UYwTidxdi3I/AAAAAAAAAEU/ellLeQ-E1vs/s800/google-io-lockup-2.png",
-    "title": "Google Cloud Messaging at I/O 2013",
-    "summary": "Google Cloud Messaging allows your services to efficiently send data to applications on Android devices. See what's new, and learn how to use GCM to make your apps more efficient.",
-    "keywords": ["gcm"],
-    "type": "youtube",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#gcm",
-    ],
-    "url": "https://developer.chrome.com/apps/cloudMessagingV2",
-    "timestamp": 1383243492000,
-    "image": "images/kk-chromium-icon.png",
-    "title": "Google Cloud Messaging for Chrome",
-    "summary": "Google Cloud Messaging for Chrome (GCM) is a service for signed-in Chrome users that helps developers send message data from servers to their Chrome apps and extensions.",
-    "keywords": ["gcm"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#sdkupdates"
-    ],
-    "url": "https://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Make Beautiful Android App Icons",
-    "summary": "Follow these in-depth launcher icon tips on the Android Developers blog.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-     {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#sdkupdates"
-    ],
-    "url": "https://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Localize Your Promotional Graphics",
-    "summary": "Learn how to capitalise on international audiences.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-   {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#sdkupdates"
-    ],
-    "url": "https://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Make your App Content more Accessible with App Linking",
-    "summary": "About using search and deep linking to get more users.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
-    "timestamp": 1194884220000,
-    "image": 'images/google/gps-googleplus.png',
-    "title": "Sharing interactive posts to Google+ from your Android app",
-    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
-    "keywords": ["Interactive", "Google+"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/mobile/android/",
-    "timestamp": 1194884220000,
-    "image": 'images/google/gps-googleplus.png',
-    "title": "Google+ Platform",
-    "summary": "Find out about features such as interactive posts, Hangouts, accessing basic user details and their social graphs to make your app more personal.",
-    "keywords": ["Google+"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/2528691",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "How to add multiple user accounts to your Developer Console for testing and more.",
-    "summary": "",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/mobile/android/share/deep-link",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Adding deep linking to Google+ posts shared from your Android app",
-    "summary": "",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "google/play/licensing/index.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Application Licensing",
-    "summary": "Information on the features of Google Play to protect your apps’ licences.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "design/style/writing.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Writing Style",
-    "summary": "Android Design guidelines for voice and style in your UI.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://en.wikipedia.org/wiki/XLIFF",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "XML Localisation Interchange File Format (XLIFF)",
-    "summary": "Background information on XLIFF.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1078870",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Graphic Assets for your Application",
-    "summary": "Details about the graphics you can add to your product listing.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "为你的应用的图片资源",
-    "summary": "如何在你的应用的商品详情页面上添加图片资源。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/payments/answer/2741495",
-    "timestamp": null,
-    "image": null,
-    "title": "Issuing Refunds",
-    "summary": "Help Center document describing how to issue refunds.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/payments/answer/2741495?hl=zh-Hans",
-    "timestamp": null,
-    "image": null,
-    "title": "退回訂單款項",
-    "summary": "如何退还已收取的订单款项。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
-    "timestamp": null,
-    "image": "distribute/images/gp-edu-apps-image.jpg",
-    "title": "Google play for education",
-    "summary": " ",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["localization", "pricing", "developer support"],
-    "url": "https://support.google.com/googleplay/android-developer/table/3541286",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Supported locations for distributing your apps in Google Play",
-    "summary": "Countries and regions where you can distribute your app in Google Play.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": ["localization", "pricing", "developer support"],
-    "url": "https://support.google.com/googleplay/android-developer/table/3541286?hl=zh-Hans",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "支持向Google Play用户发布应用的地区",
-    "summary": "支持向Google Play用户发布应用的国家/地区。",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["games", "localization", "quality"],
-    "url": "https://www.youtube.com/watch?v=SkHHPf3EdzE",
-    "timestamp": null,
-    "image": "https://developers.google.com/apps/images/io_2013/google-io-logo.png",
-    "title": "Level Up Your Android Game",
-    "summary": "Learn how to take your game to the next level in this Google I/O session.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["support"],
-    "url": "https://support.google.com/groups/answer/46601",
-    "timestamp": null,
-    "image": null,
-    "title": "Google Groups",
-    "summary": "Create a group for your community.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["support"],
-    "url": "https://support.google.com/plus/topic/2888488",
-    "timestamp": null,
-    "image": null,
-    "title": "Google+ Communities",
-    "summary": "Host a Google+ community for testers or users.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["monetize", "ads"],
-    "url": "https://www.google.com/doubleclick/publishers/small-business/index.html",
-    "timestamp": null,
-    "image": "https://www.google.com/doubleclick/publishers/small-business/images/define_ad.png",
-    "title": "DoubleClick for Publishers",
-    "summary": "A free ad management solution that helps growing publishers sell, schedule, deliver, and measure all of their digital ad inventory.",
-    "keywords": ["ads"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["monetize", "ads"],
-    "url": "https://support.google.com/googleplay/android-developer/topic/2985714",
-    "timestamp": null,
-    "image":"images/play_dev.jpg",
-    "title": "Policy Center: Ads",
-    "summary": "Introduction to ads and system interference policies in Google Play.",
-    "keywords": ["ads"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2611404",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Create Audience lists in Google Analytics",
-    "summary": "Find out how to use your analytics data to discover high value users and create remarketing audiences to use in AdMob.",
-    "keywords": ["ads, analytics, monetize"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://admob.blogspot.com/",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Inside Admob",
-    "summary": "Google’s official blog for news, tips, and information on the AdMob developer platform.",
-    "keywords": ["ads, analytics, monetize"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/answer/3111064",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "AdMob in-app conversion tracking",
-    "summary": "Use in-app conversion tracking to attribute revenue back to your IAP promotion campaigns and determine which ones earn you the most.",
-    "keywords": ["ads, analytics, conversions"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["monetize", "giftcards"],
-    "url": "https://play.google.com/about/giftcards/",
-    "timestamp": null,
-    "image": "images/gp-balance.png",
-    "title": "Google Play Gift Cards",
-    "summary": "Buy Google Play gift cards online or at a variety of retail stores.",
-    "keywords": ["gift card"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["monetize", "paymentmethods"],
-    "url": "https://support.google.com/googleplay/answer/2651410",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Google Play accepted payment methods",
-    "summary": "Support details on the payment methods supported in Google Play.",
-    "keywords": ["gift card"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/adwords/answer/2471188",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "AdWords Conversion Optimizer",
-    "summary": "Learn how Conversion Optimizer works to find the users who are most likely to convert and to serve them your conversion ads.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/app-conversion-tracking/",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Track conversions with the AdWords SDK or server API",
-    "summary": "Use the lightweight AdWords app SDK or server-to-server API to track remarketing conversions.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2611404",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Create Remarketing Audiences in Google Analytics",
-    "summary": "Learn how to use preconfigured audiences created by the Analytics team or create your own to use in your conversion campaigns.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/adwords/answer/1704341",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Link your Google Analytics and AdWords accounts",
-    "summary": "Gain greater insight into how AdWords is driving app engagement and conversions, and use this insight to improve your ads and app.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["plus", "social"],
-    "url": "https://plus.google.com/+AndroidDevelopers/",
-    "timestamp": null,
-    "image": "images/plus.jpg",
-    "title": "+Android Developers",
-    "summary": "Sharing news, ideas, and techniques for success.",
-    "keywords": ["+AndroidDevelopers"],
-    "type": "Google+",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["plus", "social"],
-    "url": "https://plus.google.com/+GooglePlay",
-    "timestamp": null,
-    "image": "https://lh4.googleusercontent.com/-IKezweZlcXI/AAAAAAAAAAI/AAAAAAABOvg/uK8Z0jekVE4/s120-c/photo.jpg",
-    "title": "+Google Play",
-    "summary": "News and discussion about Google Play, apps, and other content in Google+.",
-    "keywords": ["+GooglePlay"],
-    "type": "Google+",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["support", "android"],
-    "url": "support.html",
-    "timestamp": null,
-    "image": null,
-    "title": "Developer Support",
-    "summary": "Links to community and support resources for Android developers.",
-    "keywords": ["support"],
-    "type": "Google+",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Mobile App Analytics SDK",
-    "summary": "Measure everything about your app. Get started with the Google Analytics SDK for Android.",
-    "keywords": ["analytics, user behavior"],
-    "type": "sdk",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/edu/guidelines",
-    "timestamp": null,
-    "image": "https://developer.android.com/distribute/images/edu-guidelines.jpg",
-    "title": "Education Guidelines",
-    "summary": "These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.",
-    "keywords": [],
-    "type": "",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/edu/guidelines?hl=zh-Hans",
-    "timestamp": null,
-    "image": "https://developer.android.com/distribute/images/edu-guidelines.jpg",
-    "title": "Education Guidelines",
-    "summary": "These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.",
-    "keywords": [],
-    "type": "",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/edu/faq",
-    "timestamp": null,
-    "image": "https://developer.android.com/distribute/images/gpfe-faq.jpg",
-    "title": "Education FAQ",
-    "summary": "Answers to common questions you might have about Google Play for Education.",
-    "keywords": [],
-    "type": "",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/edu/",
-    "timestamp": null,
-    "image": "https://developers.google.com/edu/images/home-android.png",
-    "title": "Chrome Apps in Google Play for Education",
-    "summary": "Find out more about Chrome apps in Google Play for Education.",
-    "keywords": [],
-    "type": "",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/edu/tablets/#tablets-family",
-    "timestamp": null,
-    "image": "https://www.google.com/edu/images/tablets/big-tablet.png",
-    "title": "Google Play for Education Tablets",
-    "summary": "Google Play for Education leverages a diverse set up tablets approved for the classroom which may help inform you how to build educational apps.",
-    "keywords": [],
-    "type": "",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.png",
-    "title": "Deer Hunter 2014 by Glu &mdash; Sign-in",
-    "summary": "Glu finds that Google Play Game Services helps improve the user experience which leads to increased player happiness. They also find that Play Games Services signed in users tend to play longer and have a higher lifetime value.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.png",
-    "title": "PBA® Bowling Challenge by Concrete Software &mdash; Quests",
-    "summary": "Concrete Software finds that Google Play Game Services' quests are a great way to create new content for users that leads to higher engagement.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.png",
-    "title": "Dragonplay Slots by Dragonplay &mdash; Sign-in",
-    "summary": "Dragonplay finds that players who sign in with Google Play Games services tend to be high quality users who were highly engaged. They also tend to be easier to convert to paying users.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.png",
-    "title": "Asphalt 8 by Gameloft &mdash; Friends invitations",
-    "summary": "Gameloft finds that Google Play Game Services users are more engaged than the average Android user and more likely to convert to paying players.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.png",
-    "title": "Eternity Warriors 3 by Glu &mdash; Gifting",
-    "summary": "Glu finds that Google Play Game Services gifting outperforms other implementations (including those with incentives) because of its seamless flow and consistent performance.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.jpg",
-    "title": "Rivals at War: Firefight by Hothead Games &mdash; Leaderboards",
-    "summary": "Hothead Games is planning to include Google Play Game Services features in all their games going forwards after seeing that players that signed in with Play Games Services tend to show higher retention and a higher average revenue.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.png",
-    "title": "Compulsive by TMSOFT &mdash; Cross-platform",
-    "summary": "TMSOFT finds that users who authenticate with Play Games Services on Android and iOS play Compulsive twice as much and purchase in-app products over four times as much.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.png",
-    "title": "Super Stickman Golf 2 by Noodlecake Studios &mdash; Multiplayer",
-    "summary": "Noodlecake Studios finds that Google Play Game Services’ multiplayer feature helps reduce attrition.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebel_DoctorWhoLegacy_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebelGames_DrWhoLegacy_pgps.png",
-    "title": "Dr. Doctor Who: Legacy by Tiny Rebel Games &mdash; Achievements",
-    "summary": "After integrating achievements and cloud services from Google Play Game Services, Tiny Rebel Games saw a dramatic increase in daily revenues as a result of an increase in daily installs and an increase in the average revenue per install.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.png",
-    "title": "Leo’s Fortune by 1337 &amp; Senri &mdash; Saved games",
-    "summary": "1337 + Senri finds that Google Play Game Services is easy to integrate and provides essential game functions like cloud saved games, achievements and leaderboards which have a very large adoption rate amongst players.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["play,protips"],
-    "url": "shareables/distribute/secrets_play/v2/web/secrets_to_app_success_v2_en.pdf",
-    "timestamp": 1447437450,
-    "image": "images/distribute/secrets_v2_banner.jpg",
-    "title": "The Secrets to App Success on Google Play",
-    "summary": "Get the updated guide full of useful features, tips, and best practices that will help you grow a successful app or game business on Google Play.",
-    "keywords": ["secrets, success, play, google"],
-    "type": "Book",
-    "category": "distribute"
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "shareables/auto/AndroidAuto-audio-apps.pdf",
-    "timestamp": null,
-    "image": "auto/images/assets/icons/media_app_playback.png",
-    "title": "Android Auto Audio Apps UI Guidelines",
-    "summary": "Guidelines for designing audio apps that work with Auto. ",
-    "keywords": ["design", "Auto", "Automotive"],
-    "type": "Design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "shareables/auto/AndroidAuto-messaging-apps.pdf",
-    "timestamp": null,
-    "image": "auto/images/assets/icons/messaging_app_notifications.png",
-    "title": "Android Auto Messaging Apps UI Guidelines",
-    "summary": "Guidelines for designing messaging apps that work with Auto. ",
-    "keywords": ["design", "Auto", "Automotive"],
-    "type": "Design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "shareables/auto/AndroidAuto-custom-colors.pdf",
-    "timestamp": null,
-    "image": "auto/images/ui/gearhead_generic_UI.png",
-    "title": "Android Auto Color Customization UI Guidelines",
-    "summary": "Guidelines for color-customizing apps that work with Auto. ",
-    "keywords": ["design", "Auto", "Automotive"],
-    "type": "Design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "http://www.youtube.com/watch?v=RRelFvc6Czo",
-    "timestamp": null,
-    "image": "https://i1.ytimg.com/vi/RRelFvc6Czo/maxresdefault.jpg",
-    "title": "Android Developer Story: Smule",
-    "summary": "The creators of AutoRap, Magic Piano, and Songify talk about their experiences launching on Android and the explosive global growth they've seen on Google Play.",
-    "keywords": ["success", "users"],
-    "type": "video",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Mobile Analytics Implementation Guide",
-    "summary": "Learn how you can implement additional Google Analytics features to better understand your users and their behavior.",
-    "keywords": ["analytics", "Play", "users"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/tagmanager/",
-    "timestamp": null,
-    "image": "https://www.google.com/tagmanager/images/gtm-hero-illustration-small.png",
-    "title": "Google Tag Manager",
-    "summary": "Google Tag Manager enables you to change configuration values in your mobile apps using the Google Tag Manager interface, without having to rebuild and resubmit application binaries to app marketplaces.",
-    "keywords": ["analytics", "tagmanager"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://analyticsacademy.withgoogle.com/course04",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Mobile App Analytics Fundamentals",
-    "summary": "This self-paced online course on mobile app measurement shows you how Google Analytics data can help you make your app more discoverable and profitable.",
-    "keywords": ["analytics"],
-    "type": "Open Source Project",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://github.com/googleanalytics/google-analytics-plugin-for-unity",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Analytics Plugin for Unity",
-    "summary": "If you're building games with Unity, you can now implement Analytics once and ship it on multiple platforms automatically.",
-    "keywords": ["analytics", "unity"],
-    "type": "Open Source Project",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "In-App Purchases & Ecommerce",
-    "summary": "If your app sells virtual or real goods, ecommerce tracking can help you understand what behaviors lead to purchases.",
-    "keywords": ["analytics, ecommerce"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/1032415",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Goals",
-    "summary": "Track important actions in your app as goals and measure performance against your objectives.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2568874?ref_topic=6012392",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Active Users",
-    "summary": "The active user report displays your 1-day, 7-day, 14-day and 30-day trailing active users next to each other, to help you analyze performance over time.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/events",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Events",
-    "summary": "Events let you measure granular in-app activities and understand user journeys.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/customdimsmets",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Custom Dimensions",
-    "summary": "Custom dimensions enable the association of metadata with hits, users, and sessions in Google Analytics.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/user-id",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "User ID",
-    "summary": "The User ID feature enables Google Analytics to measure user activities that span across devices.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/display-features",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Demographic Reporting",
-    "summary": "By enabling display features, you can see just how different user segments engage and monetize.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/3123906",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "User Segmentation",
-    "summary": "Segments let you compare metrics for different subsets of users to identify trends and opportunities for your apps.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Campaign Tracking",
-    "summary": "Measuring campaigns in Google Analytics enables the attribution of campaigns and traffic sources to user activity within your app.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2956981",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Google Play Integration",
-    "summary": "By linking Analytics and the Play Developer Console, you can gain additional insights into the acquisition flow.",
-    "keywords": ["play, analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/1033961",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "AdWords Integration",
-    "summary": "Link Analytics and AdWords to see the entire picture of customer behavior, from ad click or impression through your site to conversion. ",
-    "keywords": ["adwords, analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Campaign URL builder for Google Play",
-    "summary": "Easily create your URLs to track install campaigns.",
-    "keywords": ["play, analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/tagmanager/answer/6003007",
-    "timestamp": null,
-    "image": "https://www.google.com/tagmanager/images/gtm-hero-illustration-small.png",
-    "title": "In-App A/B Testing",
-    "summary": "With content experiments in Google Tag Manager you can test multiple variations of your app to find which works best.",
-    "keywords": ["tagmanager"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2785577",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Behavior Flow",
-    "summary": "The Behavior Flow report visualizes the path users traveled from one Screen or Event to the next. This report can help you discover what content keeps users engaged with your app.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/1151300",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Custom Reports",
-    "summary": "Custom Reports let you create your own reports in your Google Analytics account.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2611268",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Audience Lists &amp; Remarketing",
-    "summary": "Remarketing with Google Analytics lets you deliver targeted ads to users who've already been to your site or app. You can even base those ads on the behavior those users displayed during their sessions.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/answer/3508177",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "AdMob Integration",
-    "summary": "With Google Analytics in AdMob, you can view Google Analytics data for your linked apps from within your AdMob account.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/solutions/mobile-campaign-deep-link",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Deep-Linking",
-    "summary": "Google Analytics gives you a full view of how returning users are interacting with your app, for a holistic view beyond the install.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/answer/3508177",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "AdMob Integration",
-    "summary": "With Google Analytics in AdMob, you can view Google Analytics data for your linked apps from within your AdMob account.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2568874",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Active User Report",
-    "summary": "Active user report displays your 1-day, 7-day, 14-day and 30-day trailing active users next to each other, to help you run benchmark analyses of their performance over time.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/animation/",
-    "timestamp": null,
-    "image": "images/cards/material-animation_2x.png",
-    "title": "Animation",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/style/",
-    "timestamp": null,
-    "image": "images/cards/material-style_2x.jpg",
-    "title": "Style",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/layout/",
-    "timestamp": null,
-    "image": "images/cards/material-layout_2x.png",
-    "title": "Layout",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/components/",
-    "timestamp": null,
-    "image": "images/cards/material-components_2x.jpg",
-    "title": "Components",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/patterns/",
-    "timestamp": null,
-    "image": "images/cards/material-patterns_2x.png",
-    "title": "Patterns",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/usability/",
-    "timestamp": null,
-    "image": "images/cards/material-usability_2x.png",
-    "title": "Usability",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/resources/color-palettes.html",
-    "timestamp": null,
-    "image": "images/cards/material-color-palette_2x.jpg",
-    "title": "Color Palettes",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/resources/layout-templates.html",
-    "timestamp": null,
-    "image": "images/cards/material-layout-template_2x.jpg",
-    "title": "Layout Templates",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/resources/sticker-sheets-icons.html",
-    "timestamp": null,
-    "image": "images/cards/material-sticker-sheet_2x.jpg",
-    "title": "Sticker Sheets & Icons",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/resources/roboto-noto-fonts.html",
-    "timestamp": null,
-    "image": "images/cards/material-typography_2x.jpg",
-    "title": "Typography: Roboto and Noto Sans fonts",
-    "summary": "",
-    "keywords": [],
-    "type": "materialdesign",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "icons",
-      "material",
-      "iconography"
-    ],
-    "url": "https://www.google.com/design/icons/index.html",
-    "timestamp": null,
-    "image": "images/cards/card-material-icons-16x9_2x.jpg",
-    "title": "Material icon collection",
-    "summary": "",
-    "keywords": ["icons"],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/adwords/answer/6032059",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Setting up Mobile App Install Ads",
-    "summary": "With Mobile app installs campaigns on the Search and Display Networks, and TrueView for mobile app promotion on YouTube, you can create custom app install ads that run exclusively on phones and tablets.",
-    "keywords": ["marketing", "admob"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/nearby/",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Create features based on proximity",
-    "summary": "Build simple interactions between nearby devices and people.",
-    "keywords": ["nearby", "engage"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.youtube.com/watch?v=hultDpBS22s",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Use Nearby Messages to collaborate",
-    "summary": "Nearby Messages is perfect for setting up ad-hoc groups, collaborative sessions, or sharing resources with people in a co-located space.",
-    "keywords": ["nearby", "engage"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/beacons",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Mark up the world using beacons",
-    "summary": "Give your users better location and proximity experiences by providing a strong context signal for their devices in the form of Bluetooth low energy (BLE) beacons with Eddystone.",
-    "keywords": ["nearby", "engage"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/adwords/answer/6167164",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Best practices for Mobile App Engagement",
-    "summary": "Learn how to market to your user base to drive re-engagement with your app. ",
-    "keywords": ["marketing", "admob"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "marketing",
-      "engagement",
-      "adwords1"
-    ],
-    "url": "https://support.google.com/adwords/answer/6032073",
-    "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/adwords_64dp.png",
-    "title": "Setting up Mobile App Engagement Ads",
-    "summary": "Mobile app engagement campaigns are a great choice for advertisers focused on connecting with people who already have their app.",
-    "keywords": [
-      "marketing",
-      "engagement",
-      "adwords"
-    ],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "marketing",
-      "engagement",
-      "translate"
-    ],
-    "url": "https://support.google.com/l10n/answer/6359997",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Use the App Translation Service",
-    "summary": "The App Translation Service is a human translation service. It makes it easy to order translations for app UI strings, Play Store text, in-app purchase products, and universal app campaign ads.",
-    "keywords": [
-      "marketing",
-      "engagement",
-      "translate"
-    ],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "marketing",
-      "engagement"
-    ],
-    "url": "https://support.google.com/adwords/answer/6167162",
-    "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/adwords_64dp.png",
-    "title": "Best Practices for Mobile App Installs",
-    "summary": "Getting your mobile app discovered can be challenging. Learn how to drive downloads of your app and grow a valuable user base.",
-    "keywords": ["marketing", "adwords"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/topic/2784623",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Set up your AdMob account",
-    "summary": "Setting up your AdMob account in the right way will help you get the most value, check out the Setup and Basics guide.",
-    "keywords": ["marketing", "admob"],
-    "type": "distribute",
-    "titleFriendly": ""
-    },
-    {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://analyticsacademy.withgoogle.com/mobile-app",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Analytics Academy for Mobile Apps",
-    "summary": "Learn how to use Google Analytics to make your app more discoverable and profitable.",
-    "keywords": ["marketing", "analytics"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.udacity.com/courses/ud876-3",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Learn how to show ads in your Android app",
-    "summary": "Take this online course to learn how to use AdMob to display ads in your Android app.",
-    "keywords": ["marketing", "analytics"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/mobile-ads-sdk/download",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Admob Ads",
-    "summary": "Use the Mobile Ads SDK to start showing AdMob ads in your apps.",
-    "keywords": ["marketing", "adwords"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "AdMob Help Center",
-    "summary": "For setup assistance, general info, and fixes for specific problems check out the AdMob Help Center.",
-    "keywords": ["admob"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/answer/2753860",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "AdMob Policy Guidelines",
-    "summary": "Learn about best practices for displaying AdMob ads in your apps to maximize revenue.",
-    "keywords": ["admob"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/app-invites/",
-    "timestamp": 1383243492000,
-    "image": "images/cards/google-search_2x.png",
-    "title": "Set up App Invites",
-    "summary": "Bring new users to your apps with personal recommendations, incentives, and offers.",
-    "keywords": ["invites", "appinvites", "engagement", "getusers"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/app-indexing/",
-    "timestamp": 1383243492000,
-    "image": "images/cards/google-search_2x.png",
-    "title": "Set Up App Indexing",
-    "summary": "Surface your app content in Google seaerch. Deep link direct to your apps.",
-    "keywords": ["search", "appindexing", "engagement", "getusers"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/app-indexing/webmasters/details",
-    "timestamp": null,
-    "image": "images/cards/google-search_2x.png",
-    "title": "Index your app",
-    "summary": "Index your app today by adding deep links and verifying its official web site to ensure it starts appearing in Google Search results. ",
-    "keywords": ["appindexing","search","getusers"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/identity/sign-in/android/people",
-    "timestamp": 1383243492000,
-    "image": "images/cards/google-sign-in_2x.png",
-    "title": "Get user profile details",
-    "summary": "After users sign-in with Google, you can access their age range, language, and public profile information.",
-    "keywords": ["signin", "identity", "google"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-
-
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/identity/sign-in/android/",
-    "timestamp": "",
-    "image": "images/cards/google-sign-in_2x.png",
-    "title": "Google Sign-In",
-    "summary": "Discover how you can enhance user experiences on your website or in your app using information provided by their Google identity.",
-    "keywords": ["signin", "identity", "google"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/features/play-installs",
-    "timestamp": 1383243492000,
-    "image": "images/cards/google-sign-in_2x.png",
-    "title": "Over-the-air installs",
-    "summary": "Follow this step-by-step guide to quickly add Google Sign-in and over-the-air app installs to your website.",
-    "keywords": ["signin", "google", "installs"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/features/analytics",
-    "timestamp": 1383243492000,
-    "image": 'images/google/gps-googleplus.png',
-    "title": "Google+ Insights",
-    "summary": "Measure impressions of the over-the-air install prompt, resulting installs, and success rate by day, week, and month.",
-    "keywords": ["signin", "identity"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-
- // Online courses
-
- {
-    "title":"UX Design for Mobile Developers",
-    "titleFriendly":"",
-    "summary":"Learn how to design a 5-star app.",
-    "url":"https://www.udacity.com/course/ud849",
-    "group":"",
-    "keywords": ["mobile","ux","design"],
-    "tags": ["courses, start"],
-    "image":"images/cards/courses/mobile_ux_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Developing Android Apps",
-    "titleFriendly":"",
-    "summary":"Learn Android and build an app!",
-    "url":"https://www.udacity.com/course/ud853",
-    "group":"",
-    "keywords": ["android", "start","firstapp","sdk"],
-    "tags": ["courses, start"],
-    "image":"images/cards/courses/android_fundamentals_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Android Performance",
-    "titleFriendly":"",
-    "summary":"Optimize your apps for speed and usability.",
-    "url":"https://www.udacity.com/course/ud825",
-    "group":"",
-    "keywords": ["android, performance","battery"],
-    "tags": ["courses, performance"],
-    "image":"images/cards/courses/android_performance_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Enroll in the Android Nanodegree",
-    "titleFriendly":"",
-    "summary":"Enroll in the Android Nanodegree to build the skills to work as an Android developer.",
-    "url":"https://www.udacity.com/android",
-    "group":"",
-    "keywords": ["android, nanodegree"],
-    "tags": ["courses"],
-    "image":"images/cards/courses/android_nanodegree.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Advanced Android App Development",
-    "titleFriendly":"",
-    "summary":"Productionize and publish your apps.",
-    "url":"https://www.udacity.com/course/ud855",
-    "group":"",
-    "keywords": ["android, experts"],
-    "tags": ["courses, expert"],
-    "image":"images/cards/courses/advanced_android_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Material Design for Android Developers",
-    "titleFriendly":"",
-    "summary":"Learn how to make your apps material.",
-    "url":"https://www.udacity.com/course/ud862",
-    "group":"",
-    "keywords": ["android, design, pure, material"],
-    "tags": ["courses, start, material"],
-    "image":"images/cards/courses/android_design_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Android for Beginners",
-    "titleFriendly":"",
-    "summary":"Make your first Android app, even if you don't write code.",
-    "url":"https://www.udacity.com/course/ud837",
-    "group":"",
-    "keywords": ["android, sdk, firstapp"],
-    "tags": ["courses, start"],
-    "image":"images/cards/courses/beginning_android_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Gradle for Android and Java",
-    "titleFriendly":"",
-    "summary":"Build better apps through automation",
-    "url":"https://www.udacity.com/course/ud867",
-    "group":"",
-    "keywords": ["gradle","studio", "sdk"],
-    "tags": ["courses, gradle, sdk"],
-    "image":"images/cards/courses/gradle_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Add Location and Context to your app",
-    "titleFriendly":"",
-    "summary":"Make Your Android App Location Aware.",
-    "url":"https://www.udacity.com/course/ud876-1",
-    "group":"",
-    "keywords": ["google services, context, location"],
-    "tags": ["courses, google, location, context"],
-    "image":"images/cards/courses/android_location_course.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Analytics and Tag Manager for Android",
-    "titleFriendly":"",
-    "summary":"Use Analytics and Tag Manager in Your Apps.",
-    "url":"https://www.udacity.com/course/ud876-2",
-    "group":"",
-    "keywords": ["google services, analytics, tag manager"],
-    "tags": ["courses, google, analytics"],
-    "image":"images/cards/courses/android_analytics_course.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"AdMob for Android",
-    "titleFriendly":"",
-    "summary":"Monetize Your App by Displaying Ads.",
-    "url":"https://www.udacity.com/course/ud876-3",
-    "group":"",
-    "keywords": ["monetize, google services, ads, admob"],
-    "tags": ["courses, google, ads, admob"],
-    "image":"images/cards/courses/admob_course.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Add Maps to your Android app",
-    "titleFriendly":"",
-    "summary":"Use maps, cameras, markers and more in your app.",
-    "url":"https://www.udacity.com/course/ud876-4",
-    "group":"",
-    "keywords": ["google, maps, marker, camera"],
-    "tags": ["courses, google, maps"],
-    "image":"images/cards/courses/android_maps_course.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Add Sign-in to your Android app",
-    "titleFriendly":"",
-    "summary":"Build a Seamless Sign-In Experience.",
-    "url":"https://www.udacity.com/course/ud876-5",
-    "group":"",
-    "keywords": ["google services, signin, authorization"],
-    "tags": ["courses, google, auth"],
-    "image":"images/cards/courses/android_identity_course.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Android Wear Development",
-    "titleFriendly":"",
-    "summary":"Extend your Apps to Android Smartwatches.",
-    "url":"https://www.udacity.com/course/ud875A",
-    "group":"",
-    "keywords": ["wear, wearables, smartwatch"],
-    "tags": ["courses, wear, wearable"],
-    "image":"images/cards/courses/android_wear_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Android TV and Google Cast Development",
-    "titleFriendly":"",
-    "summary":"Extend your Apps to the Big Screen.",
-    "url":"https://www.udacity.com/course/ud875B",
-    "group":"",
-    "keywords": ["cast, living room"],
-    "tags": ["courses, cast, tv"],
-    "image":"images/cards/courses/android_tv_cast_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Android Auto Development",
-    "titleFriendly":"",
-    "summary":"Put your apps in the driver's seat.",
-    "url":"https://www.udacity.com/course/ud875C",
-    "group":"",
-    "keywords": ["auto"],
-    "tags": ["courses, auto"],
-    "image":"images/cards/courses/android_auto_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-
-
- // TODO remove this?
-  {
-    "title":"Android Wear Materials",
-    "titleFriendly":"",
-    "summary":"Drag and drop your way to beautifully designed Android Wear apps.",
-    "url":"design/downloads/index.html#Wear",
-    "group":"",
-    "keywords": ["icons","stencils","color swatches"],
-    "tags": ["icons","stencils","colorswatches"],
-    "image":"images/cards/android-wear-materials_2x.jpg",
-    "lang":"en",
-    "type":"design"
-  },
-  {
-    "title":"Watch Faces for Android Wear",
-    "titleFriendly":"",
-    "summary":"Watch faces let you customize the most prominent UI feature of Android wearables. The API is simple enough for rapid development and flexible enough to build something awesome.",
-    "url":"https://www.youtube.com/watch?v=AK38PJZmIW8&list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef",
-    "group":"",
-    "keywords": ["wear", "wearable", "watch face"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/AK38PJZmIW8/maxresdefault.jpg",
-    "lang":"en",
-    "type":"video"
-  },
-  {
-    "title":"Android Support Library",
-    "titleFriendly":"",
-    "summary":"These essential components help you build a great app that works on the huge variety of Android devices, faster.",
-    "url":"https://www.youtube.com/watch?v=3PIc-DuEU2s&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX",
-    "group":"",
-    "keywords": ["support", "compatibility"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/3PIc-DuEU2s/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Consistent Design with the AppCompat Support Library",
-    "titleFriendly":"",
-    "summary":"Getting a great looking app doesn't have to be hard: AppCompat, part of the Android Support Library, gives you a consistent design baseline that works on all Android 2.1 or higher devices.",
-    "url":"https://www.youtube.com/watch?v=5Be2mJzP-Uw&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX",
-    "group":"",
-    "keywords": ["support", "compatibility","design-code"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/5Be2mJzP-Uw/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Introducing Gradle",
-    "titleFriendly":"",
-    "summary":"Android Studio uses an entirely new and flexible Gradle-based build system. You will be able to create multiple build variants for a single project, manage library dependencies and always be sure that your application builds correctly across different environments.",
-    "url":"https://www.youtube.com/watch?v=cD7NPxuuXYY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-    "group":"",
-    "keywords": ["tools", "studio","gradle"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/cD7NPxuuXYY/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Android Studio Layout Editor",
-    "titleFriendly":"",
-    "summary":"Android Studio includes a rich, visual layout editor that helps developers create better user interfaces. It eliminates the need to deploy the APK on a real device with each change, making iterations faster and helping eliminate common errors earlier in the development process.",
-    "url":"https://www.youtube.com/watch?v=JLLnhwtDoHw&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-    "group":"",
-    "keywords": ["tools", "studio","layout"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/JLLnhwtDoHw/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Debugging and testing in Android Studio",
-    "titleFriendly":"",
-    "summary":"Learn about new debugger features in Android Studio 1.2: value inlining, quick access to referring objects and a Java .class decompiler, just to name a few. See some new tools and views that let you monitor the CPU and memory performance of your app from within the IDE. ",
-    "url":"https://www.youtube.com/watch?v=2I6fuD20qlY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-    "group":"",
-    "keywords": ["tools", "studio","debugging","profiling","performance"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/2I6fuD20qlY/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Scale with Google Cloud Platform",
-    "titleFriendly":"",
-    "summary":"Build, test, and deploy applications on Google's highly-scalable and reliable infrastructure for your web, mobile and backend solutions.",
-    "url":"https://cloud.google.com/docs/",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/cards/cloud-platform_2x.png",
-    "lang":"en",
-    "type":"distribute"
-  },
-  {
-    "title":"Opportunities & Programs",
-    "titleFriendly":"",
-    "summary":"Take advantage of the many ways you can distribute your app to consumers, students, and businesses through Google Play.",
-    "url":"distribute/googleplay/index.html#opportunities",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/cards/program-edu_2x.jpg",
-    "lang":"en",
-    "type":"distribute"
-  },
-  {
-    "title":"Join the Android for Work DevHub",
-    "titleFriendly":"",
-    "summary":"The Android for Work DevHub is a place to help developers keep up with Android in the workplace.",
-    "url":"https://www.google.com/work/android/developers/applyDevHub/",
-    "group":"",
-    "keywords": ["work", "enterprise", "isv", "devhub"],
-    "tags": [],
-    "image":"images/work/cards/work-devhub_600px.png",
-    "lang":"en",
-    "type":"Community"
-  },
-  {
-    "title":"Enterprise Mobility Managers",
-    "titleFriendly":"",
-    "summary":"Integrate Android for Work into your enterprise mobility management (EMM) solution.",
-    "url":"https://developers.google.com/android/work/",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"images/work/cards/work-cloud_600px.png",
-    "lang":"en",
-    "type":"guide"
-  },
-  {
-    "title":"Learn More About Android for Work",
-    "titleFriendly":"",
-    "summary":"Android for Work makes your favorite phones and tablets the perfect business tools.",
-    "url":"https://www.google.com/work/android/",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"images/work/cards/work-profile_600px.png",
-    "lang":"en",
-    "type":"about"
-  },
-  {
-    "title":"Build a Device Policy Controller",
-    "titleFriendly":"",
-    "summary":"Create and administer a managed profile on an employee's device.",
-    "url":"https://developers.google.com/android/work/build-dpc",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"images/work/cards/work-folder_600px.png",
-    "lang":"en",
-    "type":"guide"
-  },
-  {
-    "title":"Android for Work for Developers",
-    "titleFriendly":"",
-    "summary":"Watch the videos in this playlist to understand more about Android for Work and get tips on developing enterprise apps.",
-    "url":"https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/jQWB_-o1kz4/maxresdefault.jpg",
-    "lang":"en",
-    "type":"youtube"
-  },
-  {
-    "title":"App Configurations, Testing and Launchers",
-    "titleFriendly":"",
-    "summary":"With Android for Work you can make your apps remotely configurable. We also cover how to test your app in a managed environment.",
-    "url":"https://www.youtube.com/watch?v=39NkpWkaH8M&index=2&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/39NkpWkaH8M/maxresdefault.jpg",
-    "lang":"en",
-    "type":"youtube"
-  },
-  {
-    "title":"Building an Enterprise Ready App",
-    "titleFriendly":"",
-    "summary":"A holistic view of Android for Work for developers.",
-    "url":"https://www.youtube.com/watch?v=dH41OutAMNM&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/dH41OutAMNM/maxresdefault.jpg",
-    "lang":"en",
-    "type":"youtube"
-  },
-  {
-    "title":"Android for Work: Single Use Devices",
-    "titleFriendly":"",
-    "summary":"Single-purpose computers are everywhere, and Android can meet that need.",
-    "url":"https://www.youtube.com/watch?v=j3QC6hcpy90",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/j3QC6hcpy90/maxresdefault.jpg",
-    "lang":"en",
-    "type":"youtube"
-  },
-  {
-    "title":"Your Apps at Work",
-    "titleFriendly":"",
-    "summary":"In this Google I/O 2016 session we’ll give you details for making your app more attractive to businesses.",
-    "url":"https://www.youtube.com/watch?v=Za0OQo8DRM4",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/Za0OQo8DRM4/maxresdefault.jpg",
-    "lang":"en",
-    "type":"youtube"
-  },
-  {
-    "title":"Discover YouTube cards",
-    "titleFriendly":"",
-    "summary":"Find out more about YouTube cards, the options available, and how to use them to get the most from your YouTube content.",
-    "url":"https://support.google.com/youtube/answer/6140493",
-    "group":"",
-    "keywords": ["youtube", "video", "users", "installs"],
-    "tags": [],
-    "image":"images/cards/card-youtube_2x.png",
-    "lang":"en",
-    "type":"distribute"
-  },
-    {
-    "title":"What is YouTube account good standing?",
-    "titleFriendly":"",
-    "summary":"Learn what it means for an account to be in good standing from the YouTube Help Center.",
-    "url":"https://support.google.com/youtube/answer/2797387",
-    "group":"",
-    "keywords": ["youtube", "video", "users", "installs"],
-    "tags": [],
-    "image":"images/cards/card-youtube_2x.png",
-    "lang":"en",
-    "type":"distribute"
-  },
-  {
-    "title":"What’s New in Android N Developer Preview",
-    "titleFriendly":"",
-    "summary":"Learn all about the new features in the Android N Preview.",
-    "url":"https://www.youtube.com/watch?v=CsulIu3UaUM",
-    "group":"",
-    "keywords": ["n preview"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/CsulIu3UaUM/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Developing for Android 6.0 (Marshmallow)",
-    "titleFriendly":"",
-    "summary":"This video covers how to get started with the preview, important APIs to test and how to provide feedback on the preview.",
-    "url":"https://www.youtube.com/watch?v=yYU4DHLwoRk",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/yYU4DHLwoRk/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Google I/O 2015 - What's new in Android",
-    "titleFriendly":"",
-    "summary":"This session will highlight the most exciting new developer features of the Android platform.",
-    "url":"https://www.youtube.com/watch?v=ndBdf1_oOGA",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/ndBdf1_oOGA/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Fingerprint and payments APIs",
-    "titleFriendly":"",
-    "summary":"New fingerprint and payments APIs are introduced in M, to enable enhanced UX and security for online purchasing, banking, and retail payments.",
-    "url":"https://www.youtube.com/watch?v=VOn7VrTRlA4",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/VOn7VrTRlA4/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Introduction to Voice Interaction API",
-    "titleFriendly":"",
-    "summary":"This video covers how to use the Voice Interaction API to support system or custom voice actions.",
-    "url":"https://www.youtube.com/watch?v=OW1A4XFRuyc",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/OW1A4XFRuyc/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Android Auto Backup for Apps",
-    "titleFriendly":"",
-    "summary":"Android Backup is the automatic, cloud-based backup and restore of users’ apps when they set up a new device.",
-    "url":"https://www.youtube.com/watch?v=HXacyy0HSW0",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/HXacyy0HSW0/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"New APIs in M for Android for Work",
-    "titleFriendly":"",
-    "summary":"Android M extends Android for Work functionality with a new set of APIs for Enterprise Mobility Management providers to offer new features and policy controls to IT Departments.",
-    "url":"https://www.youtube.com/watch?v=vcSj8ln-BlE",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/vcSj8ln-BlE/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Runtime Permissions in Android 6.0 Marshmallow",
-    "titleFriendly":"",
-    "summary":"Learn how to integrate runtime permissions into your Android app.",
-    "url":"https://www.youtube.com/watch?v=C8lUdPVSzDk",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/C8lUdPVSzDk/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Introduction to Doze",
-    "titleFriendly":"",
-    "summary":"An overview of Doze and how to make sure that your app behaves as expected both in and out of Doze mode. ",
-    "url":"https://youtu.be/N72ksDKrX6c",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/N72ksDKrX6c/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"The Nexus 5X, Nexus 6P and Android Marshmallow",
-    "titleFriendly":"",
-    "summary":"The new Nexus 5X and Nexus 6P along with some of the most significant developer features in the latest Android release,.",
-    "url":"https://youtu.be/U9tw5ypqEN0",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/U9tw5ypqEN0/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Asking For Permission Fine",
-    "titleFriendly":"",
-    "summary":"Picking the right way and time to ask for a permission is critical to it being granted. ",
-    "url":"https://youtu.be/iZqDdvhTZj0",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/iZqDdvhTZj0/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Data Binding Library",
-    "titleFriendly":"",
-    "summary":"Data Binding Library is a way to write declarative layouts and minimize the glue code necessary to bind your application logic and layouts. ",
-    "url":"https://youtu.be/5sCQjeGoE7M",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/5sCQjeGoE7M/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"App Links",
-    "titleFriendly":"",
-    "summary":"App Links is a new feature of Android Marshmallow that brings a faster way of opening website links for domains that you own.",
-    "url":"https://youtu.be/LQoohRwojmw",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/LQoohRwojmw/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Android M Permissions",
-    "titleFriendly":"",
-    "summary":"An introduction to Android M runtime permissions in Android M from Google I/O 2015. ",
-    "url":"https://www.youtube.com/watch?v=f17qe9vZ8RM",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/f17qe9vZ8RM/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "lang": "ja",
-    "title": "Gaming Everywhere",
-    "titleFriendly": "",
-    "summary": "東京ゲームショウ 2014 の基調講演より。",
-    "url": "https://www.youtube.com/watch?v=xelYnWcYkuE",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://img.youtube.com/vi/xelYnWcYkuE/hqdefault.jpg",
-    "type": "youtube"
-  },
-  {
-    "lang": "ja",
-    "title": "Playtime Tokyo",
-    "titleFriendly": "",
-    "summary": "アプリビジネスのノウハウを各担当者が講演しました。",
-    "url": "https://www.youtube.com/playlist?list=PLCOC_kP3nqGIHEgwm9mybvA04Vn4Cg9nn",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://img.youtube.com/vi/lJdjY3z6-LY/hqdefault.jpg",
-    "type": "youtube"
-  },
-  {
-    "lang": "ja",
-    "title": "Android Wear 関連の動画に日本語字幕が付きました",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevjp.blogspot.jp/2014/12/android-wear.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://i1.ytimg.com/vi/4JcDYkgqksY/maxresdefault.jpg",
-    "type": "blog"
-  },
-  {
-    "lang": "ja",
-    "title": "Android Studio 1.0 をリリースしました",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevjp.blogspot.jp/2014/12/android-studio-10.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://3.bp.blogspot.com/-1hV3sD1At74/VIaQSWBasUI/AAAAAAAABAU/9vYLJMsmMuQ/s1600/studio-logo.png",
-    "type": "blog"
-  },
-  {
-    "lang": "ja",
-    "title": "Google Play 開発者サービス 6.5 のご紹介",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevjp.blogspot.jp/2014/12/google-play-65.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://1.bp.blogspot.com/-4BNREC0Jojo/VGo7ahW35wI/AAAAAAAABAc/9thZl94F6fY/s1600/GMS%2B-%2BRelease%2BBlog%2BNacho%2B-%2BMap%2BToolbar.png",
-    "type": "blog"
-  },
-  {
-    "lang": "ja",
-    "title": "Alpha and Beta Testing",
-    "titleFriendly": "",
-    "summary": "アプリのローンチにまつわるリスクを最小限にするために必須のツールです。[英語コンテンツ]",
-    "url": "intl/ja/distribute/googleplay/developer-console.html#alpha-beta",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "images/gp-dc-ab.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Finding Success on Google Play",
-    "titleFriendly": "",
-    "summary": "Google Play での成功の秘訣がこの一冊に。[英語コンテンツ]",
-    "url": "intl/ja/distribute/googleplay/guide.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/play_dev_guide_b.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Core App Quality",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "intl/ja/distribute/essentials/quality/core.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "images/gp-core-quality.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Google Play アプリ ポリシー センター",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ja",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389356_en_v0",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Developer Support",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "intl/ja/support.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Wear App Quality",
-    "titleFriendly": "",
-    "summary": "いよいよウェアラブルの時代が到来。[英語コンテンツ]",
-    "url": "intl/ja/distribute/essentials/quality/wear.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/gp-wear-quality.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Google Cloud Platform が支える、新感覚リアルタイム RPG ユニゾンリーグ - 株式会社エイチームの GCP 導入事例",
-    "titleFriendly": "",
-    "summary": "スケーラブルなバックエンドを実現する Google Cloud Platform の最新導入事例。",
-    "url": "https://googleforwork-japan.blogspot.jp/2014/12/gcp-google-cloud-platform-rpg-gcp.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://3.bp.blogspot.com/-xp7KoPkbne4/VI_PfoFil3I/AAAAAAAAA3U/-k1UZ0zjCBc/s1600/unison-league.jpeg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Monetize with Ads",
-    "titleFriendly": "",
-    "summary": "アプリ内広告成功のコツがここに。[英語コンテンツ]",
-    "url": "intl/ja/distribute/monetize/ads.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/advertising.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "구글 플레이 2015년 비전",
-    "titleFriendly": "",
-    "summary": "G-Star 구글 컨퍼런스",
-    "url": "https://www.youtube.com/watch?v=7X9Ue0Nfdh4&index=2&list=PL_WJkTbDHdBksDBRoqfeyLchEQqBAOlNl",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://img.youtube.com/vi/7X9Ue0Nfdh4/hqdefault.jpg",
-    "type": "youtube"
-  },
-  {
-    "lang": "ko",
-    "title": "구글 플레이 게임",
-    "titleFriendly": "",
-    "summary": "게임 프로필, 퀘스트, 세이브드 게임 등의 신기능 소개",
-    "url": "https://www.youtube.com/watch?v=83FpwuschCQ",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://img.youtube.com/vi/83FpwuschCQ/hqdefault.jpg",
-    "type": "youtube"
-  },
-  {
-    "lang": "ko",
-    "title": "안드로이드 5.0 롤리팝을 맞이하는 개발자를 위한 안내서",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevkr.blogspot.com/2014/11/android50guidefordevelopers.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://lh5.googleusercontent.com/0Gx4Ob_WvIgNOMv3hVMuUm4O7KuSWyxCEFIvy39_6fgXh2q2azqjZf3bpZoEk-LMW-K8GwYMfyYfMUAwp38hhPQ6WFNnddhN2E2_GF3-XBQI_qjhISviz10h_mGgDWsZKA",
-    "type": "blog"
-  },
-  {
-    "lang": "ko",
-    "title": "안드로이드 앱을 위한 머티리얼 디자인 체크 리스트",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevkr.blogspot.com/2014/10/material-design-on-android-checklist.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://lh4.googleusercontent.com/JKoxeDdmsj6gYHV8rmp96U1jHj7FKeMzGBaaFu35kXp5EpJR9Ei9MQFAYghjwJoycdgydw-FZTuFNY8pDx63MWhy37rKC96ajoDXEMzvo9W0sj5yC2-uSYJdhpazVOP2cA",
-    "type": "blog"
-  },
-  {
-    "lang": "ko",
-    "title": "App Compat 라이브러리",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevkr.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://2.bp.blogspot.com/-7fF9ayZ6PgI/U9iFpk5FNEI/AAAAAAAAAs0/4P4SCvdB_4M/s640/image00.png",
-    "type": "blog"
-  },
-  {
-    "lang": "ko",
-    "title": "Alpha and Beta Testing",
-    "titleFriendly": "",
-    "summary": "출시 전에 완벽한 사전 테스트 [영문]",
-    "url": "intl/ko/distribute/googleplay/developer-console.html#alpha-beta",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "images/gp-dc-ab.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Finding Success on Google Play",
-    "titleFriendly": "",
-    "summary": "구글 플레이에서 성공하는 비결 [영문]",
-    "url": "intl/ko/distribute/googleplay/guide.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/play_dev_guide_b.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Core App Quality",
-    "titleFriendly": "",
-    "summary": "고품질 안드로이드 앱 개발 가이드 [영문]",
-    "url": "intl/ko/distribute/essentials/quality/core.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "images/gp-core-quality.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Policy Guidelines and Practices",
-    "titleFriendly": "",
-    "summary": "숙지해야할 중요한 정책 [영문]",
-    "url": "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ko",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389356_en_v0",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Developer Support",
-    "titleFriendly": "",
-    "summary": "개발자 지원 센터 활용 [영문]",
-    "url": "intl/ko/support.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://lh3.googleusercontent.com/-mGTYed3Uh-E/AAAAAAAAAAI/AAAAAAAAF58/qNYbk4mMhI0/s120-c/photo.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Wear App Quality",
-    "titleFriendly": "",
-    "summary": "웨어러블 앱 개발 가이드 [영문]",
-    "url": "intl/ko/distribute/essentials/quality/wear.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/gp-wear-quality.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Android TV 어플리케이션 개발",
-    "titleFriendly": "",
-    "summary": "앱과 게임을 거실에서 가족과 함께 [영문]",
-    "url": "intl/ko/tv/index.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "design/tv/images/atv-home.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "구글 플레이 게임 서비스",
-    "titleFriendly": "",
-    "summary": "다양한 구글 플레이 게임 서비스 기능 알아보기 [영문]",
-    "url": "intl/ko/google/play-services/games.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://developers.google.com/games/services/images/gamescreen3.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Monetize with Ads",
-    "titleFriendly": "",
-    "summary": "광고로 수익 창출하기 [영문]",
-    "url": "intl/ko/distribute/monetize/ads.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/advertising.jpg",
-    "type": "distribute"
-  },
-  {
-    "url":"https://www.youtube.com/watch?v=QDM52bblwlg",
-    "image": "images/distribute/hero-family-discovery.jpg",
-    "title": "Introducing the new family discovery experience on Google Play",
-    "summary": "Help families create little moments on Google Play. Opt-in your apps now.",
-    "tags":["families","googleplay"],
-    "type":"youtube"
-  },
-  {
-    "url":"https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
-    "image": "https://i1.ytimg.com/vi/wcjqBSei3a0/maxresdefault.jpg",
-    "title": "Developers connecting the world through Google Play",
-    "summary": "The mobile ecosystem is empowering developers to make good on the dream of connecting the world through technology to improve people's lives.",
-    "tags":["io15","googleplay"],
-    "keywords":["Google I/O 2015","io"],
-    "type":"youtube"
-  },
-  {
-    "url":"https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
-    "image": "https://i1.ytimg.com/vi/B6ydLpkhq04/maxresdefault.jpg",
-    "title": "Store Listing Experiments for Google Play",
-    "summary": "Learn how to use Google Play’s new store listing optimization feature to get more installs of your app, and how to test different graphics and text to find out which options perform the best. ",
-    "tags":["io15","googleplay","store listing"],
-    "tags":["google i/o","google play","store listing"],
-    "type":"youtube"
-  },
-  {
-    "url":"https://www.youtube.com/watch?v=jyO3-rF4Mu0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
-    "image": "https://i1.ytimg.com/vi/jyO3-rF4Mu0/maxresdefault.jpg",
-    "title": "Growing games with Google",
-    "summary": "The games industry has never been more promising and full of opportunities. This talk covers how Google is helping developers across a broad range of existing and emerging platforms.",
-    "tags":["io15","android", "googleplay","games"],
-    "keywords":["Google I/O","google play","games"],
-    "type":"youtube"
-  },
-  {
-    "url":"https://www.youtube.com/watch?v=yJisuP94lHU",
-    "image": "images/distribute/hero-playtime-opener.jpg",
-    "title": "Playtime 2015: Innovation happens everywhere",
-    "type":"Video",
-    "tags":["googleplay"],
-    "summary": "Watch the opening video from Google Play's annual event series, Playtime, which celebrates inspirational developers who are changing the world around them.",
-  },
-{
-    "url":"https://www.youtube.com/watch?v=JrR6o5tYMWQ",
-    "image": "images/distribute/hero-acquisition-devbyte.jpg",
-    "title": "User acquisition and tracking on Google Play",
-    "type" : "Video",
-    "tags" : "users,googleplay,googleio",
-    "summary": "Learn how to get new users, using Universal app campaigns directly within the Google Play Developer Console to increase your installs from ads, and find out how your acquisition channels perform.",
-  },
-]);
-
-var CAROUSEL_OVERRIDE = {
-  "distribute/googleplay/guide.html": {
-    "image": "images/distribute/hero-secrets-to-app-success.jpg",
-    "title": "The Secrets to App Success on Google Play",
-    "summary": "Get the updated guide full of useful features, tips, and best practices that will help you grow a successful app or game business on Google Play.",
-  },
-  "about/versions/lollipop.html": {
-    "image": "images/home/hero-lollipop_2x.png",
-    "heroColor": "#263238",
-    "heroInvert": true,
-    "title": "Android 5.0 Lollipop",
-    "summary": "The Android 5.0 update adds a variety of new features for your apps, such as notifications on the lock screen, an all-new camera API, OpenGL ES 3.1, the new naterial design interface, and much more.",
-  },
-  "http://www.youtube.com/watch?v=Pms0pcyPbAM": {
-    "url":"https://www.youtube.com/watch?v=Pms0pcyPbAM&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c]",
-    "image": "images/distribute/hero-carousel-giftedmom.jpg",
-    "title": "Gifted Mom reaches more mothers across Africa with Android",
-    "type":"youtube",
-    "summary": "Gifted Mom is an app developed in Cameroon which provides users with critical information about pregnancy, breastfeeding and child vaccinations. Hear the creators explain how they built their business on Google Play.",
-  },
-  "http://www.youtube.com/watch?v=9m6MoBM-sFI": {
-    "url":"https://www.youtube.com/watch?v=9m6MoBM-sFI&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c&index=3",
-    "image": "images/distribute/hero-carousel-sgn.jpg",
-    "title": "SGN increases installs with Store Listing Experiments",
-    "type" : "youtube",
-    "summary": "Watch mobile game developer SGN talk about how using Store Listing Experiments to test multiple variants across their portfolio of games helped improve their ROI, conversion rates and gamer retention.",
-  },
-  "http://www.youtube.com/watch?v=e7t3svG9PTk": {
-    "url":"https://www.youtube.com/watch?v=e7t3svG9PTk&index=2&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c",
-    "image": "images/distribute/hero-carousel-djit.jpg",
-    "title": "DJiT builds higher quality experiences on Android",
-    "type" : "youtube",
-    "summary": "Learn how Music app developer DJiT create higher quality apps with improved latency on Android Marshmallow, as well as other Android and Google Play features.",
-  },
-  "http://www.youtube.com/watch?v=J3IvOfvH1ys": {
-    "url":"https://www.youtube.com/watch?v=J3IvOfvH1ys&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c&index=1",
-    "image": "images/distribute/hero-carousel-wego.jpg",
-    "title": "Wego increases user retention with material design",
-    "type" : "youtube",
-    "summary": "Hear how online travel marketplace Wego, increased monthly user retention by 300% and reduced uninstall rates by up to 25% with material design.",
-  },
-  "https://www.youtube.com/watch?v=QDM52bblwlg": {
-    "url":"distribute/googleplay/families/about.html",
-    "image": "images/distribute/hero-family-discovery.jpg",
-    "title": "Designed for families",
-    "summary": "Introducing the new family discovery experience in Google Play. Your apps can benefit from enhanced discoverability and maintain their existing categories, rankings, and reviews elsewhere in the store. Opt-in your apps today.",
-    "type":"distribute",
-  },
-  "https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
-    "url":"https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
-    "image": "images/distribute/hero-IO15-google-play.jpg",
-    "title": "Connecting the world through Google Play",
-    "tags":["io15"],
-    "summary": "In this this Google I/O talk, hear how the mobile ecosystem is empowering developers to connect the world through technology and improve people's lives.",
-  },
-  "https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
-    "image": "images/distribute/hero-store-listing-experience.jpg",
-    "title": "Using Google Play store listing experiments",
-    "tags":["io15"],
-    "summary": "Learn how to use Google Play store listing experiments to get more installs in this Google I/O talk. Test different graphics and text to find out which options perform the best. ",
-  },
-  "https://www.youtube.com/watch?v=jyO3-rF4Mu0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
-    "image": "images/distribute/hero-IO15-growing-games.jpg",
-    "title": "Growing games with Google",
-    "tags":["io15"],
-    "summary": "The games industry has never been more promising and full of opportunities. This talk from Google I/O 2015 covers how Google is helping developers across a broad range of existing and emerging platforms.",
-  }
-};
diff --git a/docs/html/sdk/1.0_r1/installing.jd b/docs/html/sdk/1.0_r1/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.0_r1/installing.jd
+++ b/docs/html/sdk/1.0_r1/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.0_r1/requirements.jd b/docs/html/sdk/1.0_r1/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.0_r1/requirements.jd
+++ b/docs/html/sdk/1.0_r1/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.0_r2/installing.jd b/docs/html/sdk/1.0_r2/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.0_r2/installing.jd
+++ b/docs/html/sdk/1.0_r2/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.0_r2/requirements.jd b/docs/html/sdk/1.0_r2/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.0_r2/requirements.jd
+++ b/docs/html/sdk/1.0_r2/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.1_r1/installing.jd b/docs/html/sdk/1.1_r1/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.1_r1/installing.jd
+++ b/docs/html/sdk/1.1_r1/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.1_r1/requirements.jd b/docs/html/sdk/1.1_r1/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.1_r1/requirements.jd
+++ b/docs/html/sdk/1.1_r1/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r1/installing.jd b/docs/html/sdk/1.5_r1/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.5_r1/installing.jd
+++ b/docs/html/sdk/1.5_r1/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r1/requirements.jd b/docs/html/sdk/1.5_r1/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.5_r1/requirements.jd
+++ b/docs/html/sdk/1.5_r1/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r2/installing.jd b/docs/html/sdk/1.5_r2/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.5_r2/installing.jd
+++ b/docs/html/sdk/1.5_r2/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r2/requirements.jd b/docs/html/sdk/1.5_r2/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.5_r2/requirements.jd
+++ b/docs/html/sdk/1.5_r2/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r3/installing.jd b/docs/html/sdk/1.5_r3/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.5_r3/installing.jd
+++ b/docs/html/sdk/1.5_r3/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r3/requirements.jd b/docs/html/sdk/1.5_r3/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.5_r3/requirements.jd
+++ b/docs/html/sdk/1.5_r3/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.6_r1/installing.jd b/docs/html/sdk/1.6_r1/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.6_r1/installing.jd
+++ b/docs/html/sdk/1.6_r1/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.6_r1/requirements.jd b/docs/html/sdk/1.6_r1/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.6_r1/requirements.jd
+++ b/docs/html/sdk/1.6_r1/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/tv/index.jd b/docs/html/tv/index.jd
index 7c958c0..6ecc1ea 100644
--- a/docs/html/tv/index.jd
+++ b/docs/html/tv/index.jd
@@ -13,7 +13,7 @@
 
 <style>
 .fullpage>#footer,
-#jd-content>.content-footer.wrap {
+#body-content>.content-footer.wrap {
   display:none;
 }
 </style>
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index f5e9e87..f9bdef5 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -9,7 +9,7 @@
 
 <style>
 .fullpage>#footer,
-#jd-content>.content-footer.wrap {
+#body-content>.content-footer.wrap {
   display:none;
 }
 </style>
diff --git a/docs/html/wear/preview/index.jd b/docs/html/wear/preview/index.jd
index 4b3c1f2..6292577 100644
--- a/docs/html/wear/preview/index.jd
+++ b/docs/html/wear/preview/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light" style="background-color:#FFFFFF">
   <div class="wrap" style="max-width:1100px;margin-top:0">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
@@ -55,7 +45,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -77,22 +67,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-
-    <div class="actions">
-      <div><a href="{@docRoot}wear/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Report an issue
-      </a></div>
-      <div><a href="http://g.co/androidweardev">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Join developer community
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light"><div class="wrap">
   <h1 class="dac-section-title">Resources</h1>
   <div class="dac-section-subtitle">
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9adcc8b..289a72f 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -433,6 +433,9 @@
     prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
     if (info.out.canDrawThisFrame) {
         draw();
+    } else {
+        // wait on fences so tasks don't overlap next frame
+        waitOnFences();
     }
 }
 
@@ -500,6 +503,10 @@
         for (const sp<RenderNode>& node : mRenderNodes) {
             node->destroyHardwareResources(observer);
         }
+        Caches& caches = Caches::getInstance();
+        // Make sure to release all the textures we were owning as there won't
+        // be another draw
+        caches.textureCache.resetMarkInUse(this);
         mRenderPipeline->onDestroyHardwareResources();
     }
 }
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a3b6261..7ebe0ae 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -158,6 +158,8 @@
 
     ANDROID_API int64_t getFrameNumber();
 
+    void waitOnFences();
+
 private:
     CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
             IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
@@ -171,8 +173,6 @@
 
     void freePrefetchedLayers(TreeObserver* observer);
 
-    void waitOnFences();
-
     bool isSwapChainStuffed();
 
     SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index c9c07b3..e3b6dc6 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -104,6 +104,9 @@
 
     if (CC_LIKELY(canDrawThisFrame)) {
         context->draw();
+    } else {
+        // wait on fences so tasks don't overlap next frame
+        context->waitOnFences();
     }
 
     if (!canUnblockUiThread) {
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index 36be387..c8971f8 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -163,10 +163,6 @@
 }
 
 void OpenGLPipeline::onDestroyHardwareResources() {
-    Caches& caches = Caches::getInstance();
-    // Make sure to release all the textures we were owning as there won't
-    // be another draw
-    caches.textureCache.resetMarkInUse(this);
     mRenderThread.renderState().flush(Caches::FlushMode::Layers);
 }
 
diff --git a/libs/hwui/tests/scripts/prep_fugu.sh b/libs/hwui/tests/scripts/prep_fugu.sh
new file mode 100755
index 0000000..04a3203
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_fugu.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+cpubase=/sys/devices/system/cpu
+gov=cpufreq/scaling_governor
+
+adb root
+adb wait-for-device
+thermal=$(adb shell "getprop persist.service.thermal")
+echo "thermal status: $thermal"
+if [ $thermal -eq 1 ]
+then
+    echo "Trying to setprop persist.service.thermal 0 and reboot"
+    adb shell "setprop persist.service.thermal 0"
+    adb reboot
+    adb wait-for-device
+    thermal=$(adb shell "getprop persist.service.thermal")
+    if [ $thermal -eq 1 ]
+    then
+        echo "thermal property is still 1. Abort."
+        exit -1
+    fi
+    echo "Successfully setup persist.service.thermal to 0"
+fi
+
+adb shell stop perfprod
+
+# cores
+# 1833000 1750000 1666000 1583000 1500000 1416000 1333000 1250000
+# 1166000 1083000 1000000 916000 833000 750000 666000 583000 500000
+
+cpu=0
+S=1166000
+while [ $((cpu < 3)) -eq 1 ]; do
+    echo "Setting cpu ${cpu} & $(($cpu + 1)) cluster to $S hz"
+    # cpu0/online doesn't exist, because you can't turned it off, so ignore results of this command
+    adb shell "echo 1 > $cpubase/cpu${cpu}/online" &> /dev/null
+    adb shell "echo userspace > $cpubase/cpu${cpu}/$gov"
+    adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_max_freq"
+    adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_min_freq"
+    adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_setspeed"
+    cpu=$(($cpu + 2))
+done
+
+#/sys/class/devfreq/dfrgx/available_frequencies is empty, so set to min
+echo "performance mode, 457 MHz"
+adb shell "echo performance > /sys/class/devfreq/dfrgx/governor"
+adb shell "echo 457000 > /sys/class/devfreq/dfrgx/min_freq"
+adb shell "echo 457000 > /sys/class/devfreq/dfrgx/max_freq"
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 8935b72..8ae6e6b 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -258,6 +258,8 @@
                     title = uri.getLastPathSegment();
                 }
             }
+        } else {
+            title = context.getString(com.android.internal.R.string.ringtone_silent);
         }
 
         if (title == null) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
index 4f5152a..77928942 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
@@ -16,12 +16,8 @@
 
 package com.android.keyguard;
 
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.RenderNode;
-import android.view.RenderNodeAnimator;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.AnimationUtils;
@@ -144,9 +140,10 @@
         setTranslationY(0);
         AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */,
                 mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator());
-        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor.isUserUnlocked()
-                ? mDisappearAnimationUtils
-                : mDisappearAnimationUtilsLocked;
+        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
+                .needsSlowUnlockTransition()
+                        ? mDisappearAnimationUtils
+                        : mDisappearAnimationUtilsLocked;
         disappearAnimationUtils.startAnimation2d(mViews,
                 new Runnable() {
                     @Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 69eb538..7d1a6fb 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -408,9 +408,9 @@
 
     @Override
     public boolean startDisappearAnimation(final Runnable finishRunnable) {
-        float durationMultiplier = mKeyguardUpdateMonitor.isUserUnlocked()
-                ? 1f
-                : DISAPPEAR_MULTIPLIER_LOCKED;
+        float durationMultiplier = mKeyguardUpdateMonitor.needsSlowUnlockTransition()
+                ? DISAPPEAR_MULTIPLIER_LOCKED
+                : 1f;
         mLockPatternView.clearPattern();
         enableClipping(false);
         setTranslationY(0);
@@ -419,9 +419,10 @@
                 -mDisappearAnimationUtils.getStartTranslation(),
                 mDisappearAnimationUtils.getInterpolator());
 
-        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor.isUserUnlocked()
-                ? mDisappearAnimationUtils
-                : mDisappearAnimationUtilsLocked;
+        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
+                .needsSlowUnlockTransition()
+                        ? mDisappearAnimationUtilsLocked
+                        : mDisappearAnimationUtils;
         disappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
                 () -> {
                     enableClipping(true);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0566177..874eb94 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -34,9 +34,12 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.hardware.fingerprint.FingerprintManager;
@@ -159,6 +162,9 @@
 
     private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
 
+    private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
+            "com.android.settings", "com.android.settings.FallbackHome");
+
     private static KeyguardUpdateMonitor sInstance;
 
     private final Context mContext;
@@ -177,7 +183,7 @@
     private boolean mGoingToSleep;
     private boolean mBouncer;
     private boolean mBootCompleted;
-    private boolean mUserUnlocked;
+    private boolean mNeedsSlowUnlockTransition;
     private boolean mHasLockscreenWallpaper;
 
     // Device provisioning state
@@ -572,8 +578,8 @@
                 && !hasFingerprintUnlockTimedOut(sCurrentUser);
     }
 
-    public boolean isUserUnlocked() {
-        return mUserUnlocked;
+    public boolean needsSlowUnlockTransition() {
+        return mNeedsSlowUnlockTransition;
     }
 
     public StrongAuthTracker getStrongAuthTracker() {
@@ -1438,7 +1444,18 @@
     private void handleKeyguardReset() {
         if (DEBUG) Log.d(TAG, "handleKeyguardReset");
         updateFingerprintListeningState();
-        mUserUnlocked = mUserManager.isUserUnlocked(getCurrentUser());
+        mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
+    }
+
+    private boolean resolveNeedsSlowUnlockTransition() {
+        if (mUserManager.isUserUnlocked(getCurrentUser())) {
+            return false;
+        }
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME);
+        ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(homeIntent,
+                0 /* flags */);
+        return FALLBACK_HOME_COMPONENT.equals(resolveInfo.getComponentInfo().getComponentName());
     }
 
     /**
diff --git a/packages/SystemUI/res/drawable-nodpi/play.xml b/packages/SystemUI/res/drawable-nodpi/play.xml
index 747e60b..7720230 100644
--- a/packages/SystemUI/res/drawable-nodpi/play.xml
+++ b/packages/SystemUI/res/drawable-nodpi/play.xml
@@ -21,7 +21,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M8.0,5.0l0.0,14.0l11.0,-7.0z"/>
-    <path
-        android:pathData="M0 0h24v24H0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/car_ic_arrow.xml b/packages/SystemUI/res/drawable/car_ic_arrow.xml
index 9d292cc..2c5ad27 100644
--- a/packages/SystemUI/res/drawable/car_ic_arrow.xml
+++ b/packages/SystemUI/res/drawable/car_ic_arrow.xml
@@ -21,7 +21,4 @@
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
-    <path
-        android:pathData="M0 0h48v48H0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
index 7ddb40c..314a25a 100644
--- a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
+++ b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
@@ -18,9 +18,6 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
-
-    <path
-        android:pathData="M0 0h24v24H0z" />
     <path
         android:fillColor="#FFFFFF"
         android:pathData="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml b/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
index 6519673..1183203 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
@@ -19,7 +19,6 @@
         android:height="24dp"
         android:viewportWidth="24"
         android:viewportHeight="24">
-    <path android:pathData="M0 0h24v24H0z" />
     <path android:fillColor="@color/ksh_key_item_color"
             android:pathData="M22 3H7c-.69 0-1.23 .35 -1.59 .88 L0 12l5.41 8.11c.36 .53 .9 .89
 1.59 .89 h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml b/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
index 599f350..66b1307 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
@@ -19,7 +19,6 @@
         android:height="24dp"
         android:viewportWidth="24"
         android:viewportHeight="24">
-    <path android:pathData="M0 0h24v24H0z" />
    <path android:fillColor="@color/ksh_key_item_color"
             android:pathData="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_left.xml b/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
index 038187e8..57d0423e9c 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
@@ -21,5 +21,4 @@
         android:viewportHeight="24">
     <path android:fillColor="@color/ksh_key_item_color"
             android:pathData="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" />
-    <path android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml b/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
index 1e2195e..be8fe8c 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
@@ -24,5 +24,4 @@
 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27 .28 v.79l5 4.99L20.49
 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5
 14z" />
-    <path android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_right.xml b/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
index f2d7315..720d4e4 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
@@ -21,5 +21,4 @@
         android:viewportHeight="24">
     <path android:fillColor="@color/ksh_key_item_color"
             android:pathData="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
-    <path android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_up.xml b/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
index 36a83b1..350c994 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
@@ -21,5 +21,4 @@
         android:viewportHeight="24">
     <path android:fillColor="@color/ksh_key_item_color"
             android:pathData="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z" />
-    <path android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
index d9a4f7b..5b65f10 100644
--- a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
+++ b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
@@ -22,6 +22,4 @@
     <path
         android:fillColor="#FFFFFF"
         android:pathData="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
index b8fa99e..ddc9e8d 100644
--- a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
+++ b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
@@ -22,6 +22,4 @@
     <path
         android:fillColor="#FFFFFF"
         android:pathData="M8 5v14l11-7z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
index 4d2a35e..2dcdb71 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
@@ -19,9 +19,6 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:pathData="M0 0h26v24H0z"
-        android:fillColor="#00000000"/>
-    <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M21.0,8.5
         c0.85,0.0 1.6,0.23 2.3,0.62l2.24,-2.79
diff --git a/packages/SystemUI/res/drawable/ic_send.xml b/packages/SystemUI/res/drawable/ic_send.xml
index 6ce3672..7cac2a4 100644
--- a/packages/SystemUI/res/drawable/ic_send.xml
+++ b/packages/SystemUI/res/drawable/ic_send.xml
@@ -22,7 +22,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M4.02,42.0L46.0,24.0 4.02,6.0 4.0,20.0l30.0,4.0 -30.0,4.0z"/>
-    <path
-        android:pathData="M0 0h48v48H0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index f0c4e59..73f26e2 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -42,7 +42,7 @@
             android:singleLine="true"
             android:ellipsize="start"
             android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
-            android:imeOptions="actionNone|flagNoExtractUi" />
+            android:imeOptions="actionNone|flagNoExtractUi|flagNoFullscreen" />
 
     <FrameLayout
             android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4d572fb..c4bea9c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -999,6 +999,9 @@
     <!-- Footer vpn present text [CHAR LIMIT=50] -->
     <string name="vpn_footer">Network may be monitored</string>
 
+    <!-- Footer vpn present text [CHAR LIMIT=50] -->
+    <string name="branded_vpn_footer">Network may be monitored</string>
+
     <!-- Monitoring dialog title for device owned devices [CHAR LIMIT=35] -->
     <string name="monitoring_title_device_owned">Device monitoring</string>
 
@@ -1035,6 +1038,9 @@
     <!-- Monitoring dialog text for single app (inside personal profile) [CHAR LIMIT=400] -->
     <string name="monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites.</string>
 
+    <!-- Monitoring dialog text for single app (inside personal profile) [CHAR LIMIT=400] -->
+    <string name="branded_monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites.</string>
+
     <!-- Monitoring dialog text for single app (inside work profile) [CHAR LIMIT=400] -->
     <string name="monitoring_description_app_work">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>. It is connected to <xliff:g id="application">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator.</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 19ae295..b9ae585 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -49,6 +49,7 @@
         Key.QS_WORK_ADDED,
     })
     public @interface Key {
+        @Deprecated
         String OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME = "OverviewLastStackTaskActiveTime";
         String DEBUG_MODE_ENABLED = "debugModeEnabled";
         String HOTSPOT_TILE_LAST_USED = "HotspotTileLastUsed";
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 15ae4ad..4ac629d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -120,11 +120,10 @@
             mFooterTextId = R.string.device_owned_footer;
             mIsVisible = true;
         } else {
-            mFooterTextId = R.string.vpn_footer;
+            boolean isBranded = mSecurityController.isVpnBranded();
+            mFooterTextId = isBranded ? R.string.branded_vpn_footer : R.string.vpn_footer;
             // Update the VPN footer icon, if needed.
-            int footerIconId = (mSecurityController.isVpnBranded()
-                ? R.drawable.ic_qs_branded_vpn
-                : R.drawable.ic_qs_vpn);
+            int footerIconId = isBranded ? R.drawable.ic_qs_branded_vpn : R.drawable.ic_qs_vpn;
             if (mFooterIconId != footerIconId) {
                 mFooterIconId = footerIconId;
                 mMainHandler.post(mUpdateIcon);
@@ -148,11 +147,15 @@
         String primaryVpn = mSecurityController.getPrimaryVpnName();
         String profileVpn = mSecurityController.getProfileVpnName();
         boolean managed = mSecurityController.hasProfileOwner();
+        boolean isBranded = deviceOwner == null && mSecurityController.isVpnBranded();
 
         mDialog = new SystemUIDialog(mContext);
-        mDialog.setTitle(getTitle(deviceOwner));
-        mDialog.setMessage(getMessage(deviceOwner, profileOwner, primaryVpn, profileVpn, managed));
-        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
+        if (!isBranded) {
+            mDialog.setTitle(getTitle(deviceOwner));
+        }
+        mDialog.setMessage(getMessage(deviceOwner, profileOwner, primaryVpn, profileVpn, managed,
+                isBranded));
+        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(isBranded), this);
         if (mSecurityController.isVpnEnabled() && !mSecurityController.isVpnRestricted()) {
             mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
         }
@@ -163,12 +166,12 @@
         return mContext.getString(R.string.status_bar_settings_settings_button);
     }
 
-    private String getPositiveButton() {
-        return mContext.getString(R.string.quick_settings_done);
+    private String getPositiveButton(boolean isBranded) {
+        return mContext.getString(isBranded ? android.R.string.ok : R.string.quick_settings_done);
     }
 
     private String getMessage(String deviceOwner, String profileOwner, String primaryVpn,
-            String profileVpn, boolean primaryUserIsManaged) {
+            String profileVpn, boolean primaryUserIsManaged, boolean isBranded) {
         // Show a special warning when the device has device owner, but --
         // TODO See b/25779452 -- device owner doesn't actually have monitoring power.
         if (deviceOwner != null) {
@@ -184,8 +187,12 @@
                 return mContext.getString(R.string.monitoring_description_app_personal_work,
                         profileOwner, profileVpn, primaryVpn);
             } else {
-                return mContext.getString(R.string.monitoring_description_app_personal,
-                        primaryVpn);
+                if (isBranded) {
+                    return mContext.getString(R.string.branded_monitoring_description_app_personal);
+                } else {
+                    return mContext.getString(R.string.monitoring_description_app_personal,
+                            primaryVpn);
+                }
             }
         } else if (profileVpn != null) {
             return mContext.getString(R.string.monitoring_description_app_work,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 7207463..a7d7df5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -34,6 +34,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -46,6 +47,7 @@
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SystemUI;
@@ -250,6 +252,19 @@
             registerWithSystemUser();
         }
         putComponent(Recents.class, this);
+
+        // Migrate the old stack active time if necessary, otherwise, it will already be managed
+        // when the tasks are loaded in the system. See TaskPersister.restoreTasksForUserLocked().
+        long lastVisibleTaskActiveTime = Prefs.getLong(mContext,
+                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
+        if (lastVisibleTaskActiveTime != -1) {
+            long uptime = SystemClock.elapsedRealtime();
+            Settings.Secure.putLongForUser(mContext.getContentResolver(),
+                    Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME,
+                    uptime - Math.max(0, System.currentTimeMillis() - lastVisibleTaskActiveTime),
+                    processUser);
+            Prefs.remove(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 7bdb1c4..1e41870 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -20,6 +20,7 @@
 import android.app.ActivityOptions;
 import android.app.TaskStackBuilder;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -170,13 +171,6 @@
             if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 // When the screen turns off, dismiss Recents to Home
                 dismissRecentsToHomeIfVisible(false);
-            } else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
-                // For the time being, if the time changes, then invalidate the
-                // last-stack-active-time, this ensures that we will just show the last N tasks
-                // the next time that Recents loads, but prevents really old tasks from showing
-                // up if the task time is set forward.
-                Prefs.putLong(RecentsActivity.this, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
-                        0);
             }
         }
     };
@@ -322,7 +316,6 @@
         // Register the broadcast receiver to handle messages when the screen is turned off
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(Intent.ACTION_TIME_CHANGED);
         registerReceiver(mSystemBroadcastReceiver, filter);
 
         getWindow().addPrivateFlags(LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION);
@@ -800,14 +793,19 @@
         EventBus.getDefault().dump(prefix, writer);
         Recents.getTaskLoader().dump(prefix, writer);
 
+        ContentResolver cr = getContentResolver();
+        long lastPersistUptime = Settings.Secure.getLong(cr,
+                Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, 0);
+        long lastVisibleTaskActiveUptime = Settings.Secure.getLongForUser(cr,
+                Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME,
+                SystemClock.elapsedRealtime(), Recents.getSystemServices().getCurrentUser());
+
         String id = Integer.toHexString(System.identityHashCode(this));
-        long lastStackActiveTime = Prefs.getLong(this,
-                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
 
         writer.print(prefix); writer.print(TAG);
         writer.print(" visible="); writer.print(mIsVisible ? "Y" : "N");
-        writer.print(" lastStackTaskActiveTime="); writer.print(lastStackActiveTime);
-        writer.print(" currentTime="); writer.print(System.currentTimeMillis());
+        writer.print(" lastPersistUptime="); writer.print(lastPersistUptime);
+        writer.print(" lastVisibleTaskActiveUptime="); writer.print(lastVisibleTaskActiveUptime);
         writer.print(" [0x"); writer.print(id); writer.print("]");
         writer.println();
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 9d9e27389..64d9831 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -60,6 +60,7 @@
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -75,6 +76,7 @@
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AssistUtils;
 import com.android.internal.os.BackgroundThread;
 import com.android.systemui.R;
@@ -199,6 +201,9 @@
      */
     private List<TaskStackListener> mTaskStackListeners = new ArrayList<>();
 
+    /** Test constructor */
+    @VisibleForTesting public SystemServicesProxy() {}
+
     /** Private constructor */
     private SystemServicesProxy(Context context) {
         mAccm = AccessibilityManager.getInstance(context);
@@ -300,7 +305,7 @@
                 rti.baseIntent = new Intent();
                 rti.baseIntent.setComponent(cn);
                 rti.description = description;
-                rti.firstActiveTime = rti.lastActiveTime = i;
+                rti.firstActiveTime = rti.lastActiveTime = SystemClock.elapsedRealtime();
                 if (i % 2 == 0) {
                     rti.taskDescription = new ActivityManager.TaskDescription(description,
                         Bitmap.createBitmap(mDummyIcon), null,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 1278b73..ecd48e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -24,13 +24,15 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
-import com.android.systemui.Prefs;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -56,6 +58,11 @@
     private static int SESSION_BEGIN_TIME = 1000 /* ms/s */ * 60 /* s/min */ * 60 /* min/hr */ *
             6 /* hrs */;
 
+    @VisibleForTesting
+    public interface SystemTimeProvider {
+        public long getTime();
+    }
+
     /** The set of conditions to load tasks. */
     public static class Options {
         public int runningTaskId = -1;
@@ -67,15 +74,46 @@
         public int numVisibleTaskThumbnails = 0;
     }
 
-    Context mContext;
+    private Context mContext;
+    @VisibleForTesting private SystemServicesProxy mSystemServicesProxy;
 
-    List<ActivityManager.RecentTaskInfo> mRawTasks;
-    TaskStack mStack;
-    ArraySet<Integer> mCurrentQuietProfiles = new ArraySet<Integer>();
+    private List<ActivityManager.RecentTaskInfo> mRawTasks;
+    private long mLastVisibileTaskActiveTime;
+    private TaskStack mStack;
+    private ArraySet<Integer> mCurrentQuietProfiles = new ArraySet<Integer>();
+    private SystemTimeProvider mTimeProvider = new SystemTimeProvider() {
+        @Override
+        public long getTime() {
+            return SystemClock.elapsedRealtime();
+        }
+    };
 
-    /** Package level ctor */
-    RecentsTaskLoadPlan(Context context) {
+    @VisibleForTesting
+    public RecentsTaskLoadPlan(Context context, SystemServicesProxy ssp) {
         mContext = context;
+        mSystemServicesProxy = ssp;
+    }
+
+    @VisibleForTesting
+    public void setInternals(List<ActivityManager.RecentTaskInfo> tasks,
+            final long currentTime, long lastVisibleTaskActiveTime) {
+        setInternals(tasks, MIN_NUM_TASKS, currentTime, lastVisibleTaskActiveTime,
+                SESSION_BEGIN_TIME);
+    }
+
+    @VisibleForTesting
+    public void setInternals(List<ActivityManager.RecentTaskInfo> tasks, int minNumTasks,
+            final long currentTime, long lastVisibleTaskActiveTime,  int sessionBeginTime) {
+        mRawTasks = tasks;
+        mLastVisibileTaskActiveTime = lastVisibleTaskActiveTime;
+        mTimeProvider = new SystemTimeProvider() {
+            @Override
+            public long getTime() {
+                return currentTime;
+            }
+        };
+        MIN_NUM_TASKS = minNumTasks;
+        SESSION_BEGIN_TIME = sessionBeginTime;
     }
 
     private void updateCurrentQuietProfilesCache(int currentUserId) {
@@ -103,9 +141,13 @@
     public synchronized void preloadRawTasks(boolean includeFrontMostExcludedTask) {
         int currentUserId = UserHandle.USER_CURRENT;
         updateCurrentQuietProfilesCache(currentUserId);
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
+        mRawTasks = mSystemServicesProxy.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
                 currentUserId, includeFrontMostExcludedTask, mCurrentQuietProfiles);
+        mLastVisibileTaskActiveTime = RecentsDebugFlags.Static.EnableMockTasks
+                ? SystemClock.elapsedRealtime()
+                : Settings.Secure.getLongForUser(mContext.getContentResolver(),
+                        Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME,
+                                0, currentUserId);
 
         // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
         Collections.reverse(mRawTasks);
@@ -134,12 +176,9 @@
                 R.string.accessibility_recents_item_will_be_dismissed);
         String appInfoDescFormat = mContext.getString(
                 R.string.accessibility_recents_item_open_app_info);
-        long lastStackActiveTime = Prefs.getLong(mContext,
-                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0);
-        if (RecentsDebugFlags.Static.EnableMockTasks) {
-            lastStackActiveTime = 0;
-        }
-        long newLastStackActiveTime = -1;
+        boolean updatedLastVisibleTaskActiveTime = false;
+        long newLastVisibileTaskActiveTime = 0;
+        long currentTime = mTimeProvider.getTime();
         int taskCount = mRawTasks.size();
         for (int i = 0; i < taskCount; i++) {
             ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
@@ -148,19 +187,20 @@
             Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent,
                     t.userId, t.firstActiveTime, t.lastActiveTime);
 
-            // This task is only shown in the stack if it statisfies the historical time or min
-            // number of tasks constraints. Freeform tasks are also always shown.
-            boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId);
-            boolean isStackTask = isFreeformTask || !isHistoricalTask(t) ||
-                    (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS));
-            boolean isLaunchTarget = taskKey.id == runningTaskId;
+            // Only show the task if it is freeform, or later than the last visible task active time
+            // and either recently used, or within the last five tasks
+            boolean isFreeformTask = mSystemServicesProxy.isFreeformStack(t.stackId);
+            boolean isRecentlyUsedTask = t.lastActiveTime >= (currentTime - SESSION_BEGIN_TIME);
+            boolean isMoreRecentThanLastVisible = t.lastActiveTime >= mLastVisibileTaskActiveTime;
+            boolean isStackTask = isFreeformTask || (isMoreRecentThanLastVisible &&
+                    (isRecentlyUsedTask || i >= (taskCount - MIN_NUM_TASKS)));
+            boolean isLaunchTarget = t.persistentId == runningTaskId;
 
-            // The last stack active time is the baseline for which we show visible tasks.  Since
-            // the system will store all the tasks, we don't want to show the tasks prior to the
-            // last visible ones, otherwise, as you dismiss them, the previous tasks may satisfy
-            // the other stack-task constraints.
-            if (isStackTask && newLastStackActiveTime < 0) {
-                newLastStackActiveTime = t.lastActiveTime;
+            // If this is the first task satisfying the stack constraints, update the baseline
+            // at which we show visible tasks
+            if (isStackTask && !updatedLastVisibleTaskActiveTime) {
+                newLastVisibileTaskActiveTime = t.lastActiveTime;
+                updatedLastVisibleTaskActiveTime = true;
             }
 
             // Load the title, icon, and color
@@ -188,9 +228,12 @@
             affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
             affiliatedTasks.put(taskKey.id, taskKey);
         }
-        if (newLastStackActiveTime != -1) {
-            Prefs.putLong(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
-                    newLastStackActiveTime);
+        if (updatedLastVisibleTaskActiveTime &&
+                newLastVisibileTaskActiveTime != mLastVisibileTaskActiveTime) {
+            Settings.Secure.putLongForUser(mContext.getContentResolver(),
+                    Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME,
+                            newLastVisibileTaskActiveTime, UserHandle.USER_CURRENT);
+            mLastVisibileTaskActiveTime = newLastVisibileTaskActiveTime;
         }
 
         // Initialize the stacks
@@ -255,11 +298,4 @@
         }
         return false;
     }
-
-    /**
-     * Returns whether this task is too old to be shown.
-     */
-    private boolean isHistoricalTask(ActivityManager.RecentTaskInfo t) {
-        return t.lastActiveTime < (System.currentTimeMillis() - SESSION_BEGIN_TIME);
-    }
 }
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 ba31e3e..e0eda37 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -30,6 +30,7 @@
 import android.util.Log;
 import android.util.LruCache;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -286,6 +287,20 @@
         }
     };
 
+    @VisibleForTesting
+    public RecentsTaskLoader() {
+        mActivityInfoCache = null;
+        mIconCache = null;
+        mThumbnailCache = null;
+        mActivityLabelCache = null;
+        mContentDescriptionCache = null;
+        mLoadQueue = null;
+        mLoader = null;
+
+        mMaxThumbnailCacheSize = 0;
+        mMaxIconCacheSize = 0;
+    }
+
     public RecentsTaskLoader(Context context) {
         Resources res = context.getResources();
         mDefaultTaskBarBackgroundColor =
@@ -332,7 +347,8 @@
 
     /** Creates a new plan for loading the recent tasks. */
     public RecentsTaskLoadPlan createLoadPlan(Context context) {
-        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context);
+        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context,
+                Recents.getSystemServices());
         return plan;
     }
 
@@ -455,7 +471,8 @@
     /**
      * Returns the cached task label if the task key is not expired, updating the cache if it is.
      */
-    String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) {
+    @VisibleForTesting public String getAndUpdateActivityTitle(Task.TaskKey taskKey,
+            ActivityManager.TaskDescription td) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Return the task description label if it exists
@@ -483,7 +500,8 @@
      * Returns the cached task content description if the task key is not expired, updating the
      * cache if it is.
      */
-    String getAndUpdateContentDescription(Task.TaskKey taskKey, Resources res) {
+    @VisibleForTesting public String getAndUpdateContentDescription(Task.TaskKey taskKey,
+            Resources res) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Return the cached content description if it exists
@@ -507,8 +525,8 @@
     /**
      * Returns the cached task icon if the task key is not expired, updating the cache if it is.
      */
-    Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
-            Resources res, boolean loadIfNotCached) {
+    @VisibleForTesting public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey,
+            ActivityManager.TaskDescription td, Resources res, boolean loadIfNotCached) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Return the cached activity icon if it exists
@@ -542,7 +560,8 @@
     /**
      * Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
      */
-    Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached) {
+    @VisibleForTesting public Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey,
+            boolean loadIfNotCached) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Return the cached thumbnail if it exists
@@ -570,7 +589,7 @@
      * Returns the task's primary color if possible, defaulting to the default color if there is
      * no specified primary color.
      */
-    int getActivityPrimaryColor(ActivityManager.TaskDescription td) {
+    @VisibleForTesting public int getActivityPrimaryColor(ActivityManager.TaskDescription td) {
         if (td != null && td.getPrimaryColor() != 0) {
             return td.getPrimaryColor();
         }
@@ -580,7 +599,7 @@
     /**
      * Returns the task's background color if possible.
      */
-    int getActivityBackgroundColor(ActivityManager.TaskDescription td) {
+    @VisibleForTesting public int getActivityBackgroundColor(ActivityManager.TaskDescription td) {
         if (td != null && td.getBackgroundColor() != 0) {
             return td.getBackgroundColor();
         }
@@ -591,7 +610,7 @@
      * Returns the activity info for the given task key, retrieving one from the system if the
      * task key is expired.
      */
-    ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
+    @VisibleForTesting public ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         ComponentName cn = taskKey.getComponent();
         ActivityInfo activityInfo = mActivityInfoCache.get(cn);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 86a0315..4191f52 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -290,7 +290,10 @@
      */
     public boolean isFreeformTask() {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        return ssp.hasFreeformWorkspaceSupport() && ssp.isFreeformStack(key.stackId);
+        if (ssp != null) {
+            return ssp.hasFreeformWorkspaceSupport() && ssp.isFreeformStack(key.stackId);
+        }
+        return false;
     }
 
     /** Notifies the callback listeners that this task has been loaded */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index e46f8f4f..a4b76ebb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -165,7 +165,7 @@
         mSkipFirstFrame = skipFirstFrame;
         mOnAnimationFinished = onAnimationFinished;
 
-        if (mKeyguardUpdateMonitor.isUserUnlocked()) {
+        if (!mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
             scheduleUpdate();
 
             // No need to wait for the next frame to be drawn for this case - onPreDraw will execute
@@ -230,9 +230,9 @@
     }
 
     private float getScrimInFrontAlpha() {
-        return mKeyguardUpdateMonitor.isUserUnlocked()
-                ? SCRIM_IN_FRONT_ALPHA
-                : SCRIM_IN_FRONT_ALPHA_LOCKED;
+        return mKeyguardUpdateMonitor.needsSlowUnlockTransition()
+                ? SCRIM_IN_FRONT_ALPHA_LOCKED
+                : SCRIM_IN_FRONT_ALPHA;
     }
 
     protected void scheduleUpdate() {
@@ -400,7 +400,7 @@
     }
 
     protected Interpolator getInterpolator() {
-        if (mAnimateKeyguardFadingOut && !mKeyguardUpdateMonitor.isUserUnlocked()) {
+        if (mAnimateKeyguardFadingOut && mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
             return KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED;
         } else if (mAnimateKeyguardFadingOut) {
             return KEYGUARD_FADE_OUT_INTERPOLATOR;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 0314ca2..b73e67f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -294,7 +294,7 @@
     public void hide(long startTime, long fadeoutDuration) {
         mShowing = false;
 
-        if (!KeyguardUpdateMonitor.getInstance(mContext).isUserUnlocked()) {
+        if (KeyguardUpdateMonitor.getInstance(mContext).needsSlowUnlockTransition()) {
             fadeoutDuration = KEYGUARD_DISMISS_DURATION_LOCKED;
         }
         long uptimeMillis = SystemClock.uptimeMillis();
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 5e4854c..3f8650a 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -78,6 +78,18 @@
         sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
                 "com.google.android.leanbacklauncher",
                 "com.google.android.leanbacklauncher.settings.HomeScreenSettingsActivity"));
+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
+                "com.google.android.apps.mediashell",
+                "com.google.android.apps.mediashell.settings.CastSettingsActivity"));
+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
+                "com.google.android.katniss",
+                "com.google.android.katniss.setting.SpeechSettingsActivity"));
+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
+                "com.google.android.katniss",
+                "com.google.android.katniss.setting.SearchSettingsActivity"));
+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
+                "com.google.android.gsf.notouch",
+                "com.google.android.gsf.notouch.UsageDiagnosticsSettingActivity"));
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
rename to packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java
index 328bf48..641cdc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java
@@ -28,7 +28,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class TouchAnimatorTests extends SysuiTestCase {
+public class TouchAnimatorTest extends SysuiTestCase {
 
     private Listener mTouchListener;
     private View mTestView;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
rename to packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index 9795027..2bfbc5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -56,7 +56,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class TileLifecycleManagerTests extends SysuiTestCase {
+public class TileLifecycleManagerTest extends SysuiTestCase {
     public static final String TILE_UPDATE_BROADCAST = "com.android.systemui.tests.TILE_UPDATE";
     public static final String EXTRA_CALLBACK = "callback";
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
rename to packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
index 9d08d33..c2237c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
@@ -34,7 +34,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class TileServiceManagerTests extends SysuiTestCase {
+public class TileServiceManagerTest extends SysuiTestCase {
 
     private TileServices mTileServices;
     private TileLifecycleManager mTileLifecycle;
@@ -52,7 +52,7 @@
         mTileLifecycle = Mockito.mock(TileLifecycleManager.class);
         Mockito.when(mTileLifecycle.isActiveTile()).thenReturn(false);
         ComponentName componentName = new ComponentName(mContext,
-                TileServiceManagerTests.class);
+                TileServiceManagerTest.class);
         Mockito.when(mTileLifecycle.getComponent()).thenReturn(componentName);
         mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mTileLifecycle);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
rename to packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 5a657e4..3ee1372 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -38,7 +38,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class TileServicesTests extends SysuiTestCase {
+public class TileServicesTest extends SysuiTestCase {
     private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
 
     private TileServices mTileService;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTaskLoadPlanTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTaskLoadPlanTest.java
new file mode 100644
index 0000000..4280ff4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTaskLoadPlanTest.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.app.ActivityManager;
+import android.support.test.runner.AndroidJUnit4;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+
+import java.util.ArrayList;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+
+
+/**
+ * Mock task loader that does not actually load any tasks.
+ */
+class MockRecentsTaskNonLoader extends RecentsTaskLoader {
+    @Override
+    public String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) {
+        return "";
+    }
+
+    @Override
+    public String getAndUpdateContentDescription(Task.TaskKey taskKey, Resources res) {
+        return "";
+    }
+
+    @Override
+    public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td, Resources res, boolean loadIfNotCached) {
+        return null;
+    }
+
+    @Override
+    public Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached) {
+        return null;
+    }
+
+    @Override
+    public int getActivityPrimaryColor(ActivityManager.TaskDescription td) {
+        return 0;
+    }
+
+    @Override
+    public int getActivityBackgroundColor(ActivityManager.TaskDescription td) {
+        return 0;
+    }
+
+    @Override
+    public ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
+        return null;
+    }
+}
+
+/**
+ * TODO(winsonc):
+ * - add test to ensure excluded tasks are loaded at the front of the list
+ * - add test to ensure the last visible task active time is migrated from absolute to uptime
+ */
+@RunWith(AndroidJUnit4.class)
+public class RecentsTaskLoadPlanTest extends SysuiTestCase {
+    private static final String TAG = "RecentsTaskLoadPlanTest";
+
+    private MockRecentsTaskNonLoader mDummyLoader = new MockRecentsTaskNonLoader();
+    private SystemServicesProxy mDummySsp = new SystemServicesProxy();
+
+    @Test
+    public void testEmptyRecents() {
+        RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(mContext, mDummySsp);
+        ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<>();
+        loadPlan.setInternals(tasks, 0 /* current */, 0 /* lastVisibleTaskActive */);
+        loadPlan.preloadPlan(mDummyLoader, 0 /* runningTaskId */,
+                false /* includeFrontMostExcludedTask */);
+        assertFalse("Expected task to be empty", loadPlan.getTaskStack().getStackTaskCount() > 0);
+    }
+
+    @Test
+    public void testLessThanEqualMinTasks() {
+        RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(mContext, mDummySsp);
+        ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<>();
+        int minTasks = 3;
+
+        resetTaskInfoList(tasks,
+                createTaskInfo(0, 1),
+                createTaskInfo(1, 2),
+                createTaskInfo(2, 3));
+
+        // Ensure that all tasks are loaded if the tasks are within the session and after the last
+        // visible active time (all tasks are loaded because there are < minTasks number of tasks)
+        loadPlan.setInternals(tasks, minTasks, 0 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
+
+        loadPlan.setInternals(tasks, minTasks, 1 /* current */, 0 /* lastVisibleTaskActive */,
+                0 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
+
+        loadPlan.setInternals(tasks, minTasks, 1 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
+
+        loadPlan.setInternals(tasks, minTasks, 3 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
+
+        loadPlan.setInternals(tasks, minTasks, 3 /* current */, 1 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
+
+        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
+
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
+
+        // Ensure that only tasks are not loaded if are after the last visible active time, even if
+        // they are within the session
+        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
+
+        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 1 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
+
+        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 2 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0);
+        assertTasksInStack(loadPlan.getTaskStack(), 1, 2);
+
+        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 3 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
+        assertTasksInStack(loadPlan.getTaskStack(), 2);
+
+        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 50 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2);
+    }
+
+    @Test
+    public void testMoreThanMinTasks() {
+        RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(mContext, mDummySsp);
+        ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<>();
+        int minTasks = 3;
+
+        // Create all tasks within the session
+        resetTaskInfoList(tasks,
+                createTaskInfo(0, 1),
+                createTaskInfo(1, 50),
+                createTaskInfo(2, 100),
+                createTaskInfo(3, 101),
+                createTaskInfo(4, 102),
+                createTaskInfo(5, 103));
+
+        // Ensure that only the tasks that are within the window but after the last visible active
+        // time is loaded, or the minTasks number of tasks are loaded if there are less than that
+
+        // Session window shifts
+        loadPlan.setInternals(tasks, minTasks, 0 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 1 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 51 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 52 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0);
+        assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 100 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0);
+        assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 101 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
+        assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 103 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
+        assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
+        assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 151 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2);
+        assertTasksInStack(loadPlan.getTaskStack(), 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 200 /* current */, 0 /* lastVisibleTaskActive */,
+                50 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2);
+        assertTasksInStack(loadPlan.getTaskStack(), 3, 4, 5);
+
+        // Last visible active time shifts (everything is in window)
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 0 /* lastVisibleTaskActive */,
+                150 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 1 /* lastVisibleTaskActive */,
+                150 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 2 /* lastVisibleTaskActive */,
+                150 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0);
+        assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 50 /* lastVisibleTaskActive */,
+                150 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0);
+        assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 51 /* lastVisibleTaskActive */,
+                150 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
+        assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 100 /* lastVisibleTaskActive */,
+                150 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
+        assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 101 /* lastVisibleTaskActive */,
+                150 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2);
+        assertTasksInStack(loadPlan.getTaskStack(), 3, 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 102 /* lastVisibleTaskActive */,
+                150 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2, 3);
+        assertTasksInStack(loadPlan.getTaskStack(), 4, 5);
+
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 103 /* lastVisibleTaskActive */,
+                150 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4);
+        assertTasksInStack(loadPlan.getTaskStack(), 5);
+
+        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 104 /* lastVisibleTaskActive */,
+                150 /* sessionBegin */);
+        loadPlan.preloadPlan(mDummyLoader, 0, false);
+        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
+    }
+
+    private ActivityManager.RecentTaskInfo createTaskInfo(int taskId, long lastActiveTime) {
+        ActivityManager.RecentTaskInfo info = new ActivityManager.RecentTaskInfo();
+        info.id = info.persistentId = taskId;
+        info.lastActiveTime = lastActiveTime;
+        return info;
+    }
+
+    private void resetTaskInfoList(ArrayList<ActivityManager.RecentTaskInfo> tasks,
+            ActivityManager.RecentTaskInfo ... infos) {
+        tasks.clear();
+        for (ActivityManager.RecentTaskInfo info : infos) {
+            tasks.add(info);
+        }
+    }
+
+    private void assertTasksInStack(TaskStack stack, int... taskIds) {
+        for (int taskId : taskIds) {
+            assertNotNull("Expected task " + taskId + " in stack", stack.findTaskWithId(taskId));
+        }
+    }
+
+    private void assertTasksNotInStack(TaskStack stack, int... taskIds) {
+        for (int taskId : taskIds) {
+            assertNull("Expected task " + taskId + " not in stack", stack.findTaskWithId(taskId));
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/phone/DozeParametersTests.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/phone/DozeParametersTests.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index b14839a..ee10440 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/phone/DozeParametersTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.systemui.phone;
+package com.android.systemui.statusbar.phone;
 
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -28,7 +28,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class DozeParametersTests {
+public class DozeParametersTest {
 
     @Test
     public void test_inOutMatcher_defaultIn() {
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 0023e4b..dc48cea 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -922,7 +922,7 @@
 
         // Record user as started so newly mounted volumes kick off events
         // correctly, then synthesize events for any already-mounted volumes.
-        synchronized (mVolumes) {
+        synchronized (mLock) {
             for (int i = 0; i < mVolumes.size(); i++) {
                 final VolumeInfo vol = mVolumes.valueAt(i);
                 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
@@ -945,7 +945,7 @@
         } catch (NativeDaemonConnectorException ignored) {
         }
 
-        synchronized (mVolumes) {
+        synchronized (mLock) {
             mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 146684f..b30b78c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -21610,6 +21610,10 @@
         synchronized (this) {
             currentUserId = mUserController.getCurrentUserIdLocked();
             targetUserInfo = mUserController.getUserInfo(targetUserId);
+            if (targetUserId == currentUserId) {
+                Slog.i(TAG, "user #" + targetUserId + " is already the current user");
+                return true;
+            }
             if (targetUserInfo == null) {
                 Slog.w(TAG, "No user info for user #" + targetUserId);
                 return false;
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 43eb251..6cdabaa 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import android.annotation.NonNull;
+import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Debug;
@@ -24,6 +25,7 @@
 import android.os.FileUtils;
 import android.os.Process;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Slog;
@@ -80,7 +82,7 @@
     private static final String PERSISTED_TASK_IDS_FILENAME = "persisted_taskIds.txt";
     static final String IMAGE_EXTENSION = ".png";
 
-    private static final String TAG_TASK = "task";
+    @VisibleForTesting static final String TAG_TASK = "task";
 
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
@@ -407,18 +409,43 @@
         return null;
     }
 
+    @VisibleForTesting
     List<TaskRecord> restoreTasksForUserLocked(final int userId) {
         final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
         ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
 
         File userTasksDir = getUserTasksDir(userId);
-
         File[] recentFiles = userTasksDir.listFiles();
         if (recentFiles == null) {
             Slog.e(TAG, "restoreTasksForUserLocked: Unable to list files from " + userTasksDir);
             return tasks;
         }
 
+        // Get the last persist uptime so we know how to adjust the first/last active times for each
+        // task
+        ContentResolver cr = mService.mContext.getContentResolver();
+        long lastPersistUptime = Settings.Secure.getLong(cr,
+                Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, 0);
+        if (DEBUG) {
+            Slog.d(TaskPersister.TAG, "restoreTasksForUserLocked: lastPersistUptime=" +
+                    lastPersistUptime);
+        }
+
+        // Adjust the overview last visible task active time as we adjust the task active times when
+        // loading. See TaskRecord.restoreFromXml().  If we have not migrated yet, SystemUI will
+        // migrate the old value into the system setting.
+        if (lastPersistUptime > 0) {
+            long overviewLastActiveTime = Settings.Secure.getLongForUser(cr,
+                    Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, 0, userId);
+            if (DEBUG) {
+                Slog.d(TaskPersister.TAG, "restoreTasksForUserLocked: overviewLastActiveTime=" +
+                        overviewLastActiveTime + " lastPersistUptime=" + lastPersistUptime);
+            }
+            Settings.Secure.putLongForUser(cr,
+                    Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME,
+                    -lastPersistUptime + overviewLastActiveTime, userId);
+        }
+
         for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
             File taskFile = recentFiles[taskNdx];
             if (DEBUG) {
@@ -439,15 +466,11 @@
                     if (event == XmlPullParser.START_TAG) {
                         if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: START_TAG name=" + name);
                         if (TAG_TASK.equals(name)) {
-                            final TaskRecord task = TaskRecord.restoreFromXml(in, mStackSupervisor);
+                            final TaskRecord task = TaskRecord.restoreFromXml(in, mService,
+                                    mStackSupervisor, lastPersistUptime);
                             if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: restored task="
                                     + task);
                             if (task != null) {
-                                // XXX Don't add to write queue... there is no reason to write
-                                // out the stuff we just read, if we don't write it we will
-                                // read the same thing again.
-                                // mWriteQueue.add(new TaskWriteQueueItem(task));
-
                                 final int taskId = task.taskId;
                                 if (mStackSupervisor.anyTaskForIdLocked(taskId,
                                         /* restoreFromRecents= */ false, 0) != null) {
@@ -463,6 +486,12 @@
                                     task.isPersistable = true;
                                     tasks.add(task);
                                     recoveredTaskIds.add(taskId);
+
+                                    // We've shifted the first and last active times, so we need to
+                                    // persist the new task data to disk otherwise they will not
+                                    // have the updated values.  This is only done once whenever
+                                    // the recents are first loaded for the user.
+                                    wakeup(task, false);
                                 }
                             } else {
                                 Slog.e(TAG, "restoreTasksForUserLocked: Unable to restore taskFile="
@@ -751,6 +780,15 @@
                         }
                     }
                 }
+
+                // Always update the task persister uptime when updating any tasks
+                if (DEBUG) {
+                    Slog.d(TAG, "LazyTaskWriter: Updating last write uptime=" +
+                            SystemClock.elapsedRealtime());
+                }
+                Settings.Secure.putLong(mService.mContext.getContentResolver(),
+                        Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME,
+                        SystemClock.elapsedRealtime());
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 0745a85..206dd45 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -39,12 +39,14 @@
 import android.os.Debug;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.DisplayMetrics;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.XmlUtils;
 
@@ -151,8 +153,10 @@
     ComponentName realActivity; // The actual activity component that started the task.
     boolean realActivitySuspended; // True if the actual activity component that started the
                                    // task is suspended.
-    long firstActiveTime;   // First time this task was active.
-    long lastActiveTime;    // Last time this task was active, including sleep.
+    long firstActiveTime;   // First time this task was active, relative to boot time. This can be
+                            // negative if this task was last used prior to boot.
+    long lastActiveTime;    // Last time this task was active, relative to boot time. This can be
+                            // negative if this task was last used prior to boot.
     boolean inRecents;      // Actually in the recents list?
     boolean isAvailable;    // Is the activity available to be launched?
     boolean rootWasReset;   // True if the intent at the root of the task had
@@ -380,14 +384,14 @@
     }
 
     void touchActiveTime() {
-        lastActiveTime = System.currentTimeMillis();
+        lastActiveTime = SystemClock.elapsedRealtime();
         if (firstActiveTime == 0) {
             firstActiveTime = lastActiveTime;
         }
     }
 
     long getInactiveDuration() {
-        return System.currentTimeMillis() - lastActiveTime;
+        return SystemClock.elapsedRealtime() - lastActiveTime;
     }
 
     /** Sets the original intent, and the calling uid and package. */
@@ -458,8 +462,9 @@
             rootWasReset = true;
         }
         userId = UserHandle.getUserId(info.applicationInfo.uid);
-        mUserSetupComplete = Settings.Secure.getIntForUser(mService.mContext.getContentResolver(),
-                USER_SETUP_COMPLETE, 0, userId) != 0;
+        mUserSetupComplete = mService != null &&
+                Settings.Secure.getIntForUser(mService.mContext.getContentResolver(),
+                        USER_SETUP_COMPLETE, 0, userId) != 0;
         if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
             // If the activity itself has requested auto-remove, then just always do it.
             autoRemoveRecents = true;
@@ -1184,7 +1189,9 @@
         if (lastTaskDescription != null) {
             lastTaskDescription.saveToXml(out);
         }
-        mLastThumbnailInfo.saveToXml(out);
+        if (mLastThumbnailInfo != null) {
+            mLastThumbnailInfo.saveToXml(out);
+        }
         out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
         out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
         out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
@@ -1206,9 +1213,11 @@
             out.endTag(null, TAG_AFFINITYINTENT);
         }
 
-        out.startTag(null, TAG_INTENT);
-        intent.saveToXml(out);
-        out.endTag(null, TAG_INTENT);
+        if (intent != null) {
+            out.startTag(null, TAG_INTENT);
+            intent.saveToXml(out);
+            out.endTag(null, TAG_INTENT);
+        }
 
         final ArrayList<ActivityRecord> activities = mActivities;
         final int numActivities = activities.size();
@@ -1227,8 +1236,9 @@
         }
     }
 
-    static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
-            throws IOException, XmlPullParserException {
+    static TaskRecord restoreFromXml(XmlPullParser in, ActivityManagerService service,
+            ActivityStackSupervisor stackSupervisor, long lastPersistUptime)
+                    throws IOException, XmlPullParserException {
         Intent intent = null;
         Intent affinityIntent = null;
         ArrayList<ActivityRecord> activities = new ArrayList<>();
@@ -1341,6 +1351,31 @@
             }
         }
 
+        if (lastPersistUptime > 0) {
+            if (TaskPersister.DEBUG) {
+                Slog.d(TaskPersister.TAG, "TaskRecord: Adjust firstActiveTime=" + firstActiveTime +
+                        " lastPersistUptime=" + lastPersistUptime);
+                Slog.d(TaskPersister.TAG, "TaskRecord: Migrate lastActiveTime=" + lastActiveTime +
+                        " lastActiveTime=" + lastPersistUptime);
+            }
+            // The first and last task active times are relative to the last boot time, so offset
+            // them to be prior to the current boot time
+            firstActiveTime = -lastPersistUptime + firstActiveTime;
+            lastActiveTime = -lastPersistUptime + lastActiveTime;
+        } else {
+            // The first/last active times are still absolute clock times, so offset them to be
+            // relative to the current boot time
+            long currentTime = System.currentTimeMillis();
+            if (TaskPersister.DEBUG) {
+                Slog.d(TaskPersister.TAG, "TaskRecord: Migrate firstActiveTime=" + firstActiveTime +
+                                " currentTime=" + currentTime);
+                Slog.d(TaskPersister.TAG, "TaskRecord: Migrate lastActiveTime=" + lastActiveTime +
+                                " currentTime=" + currentTime);
+            }
+            firstActiveTime = -Math.max(0, currentTime - firstActiveTime);
+            lastActiveTime = -Math.max(0, currentTime - lastActiveTime);
+        }
+
         int event;
         while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
                 (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
@@ -1390,7 +1425,7 @@
                     + ": effectiveUid=" + effectiveUid);
         }
 
-        final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
+        final TaskRecord task = new TaskRecord(service, taskId, intent,
                 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
                 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
                 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
@@ -1785,7 +1820,7 @@
         pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
                 pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
                 pw.print(" isResizeable=" + isResizeable());
-                pw.print(" firstActiveTime=" + lastActiveTime);
+                pw.print(" firstActiveTime=" + firstActiveTime);
                 pw.print(" lastActiveTime=" + lastActiveTime);
                 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
     }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 983cfdc..ef3c4b2 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -645,6 +645,37 @@
                 mContext.startService(startServiceIntent);
             }
         });
+
+        // Sync adapters were able to access the synced account without the accounts
+        // permission which circumvents our permission model. Therefore, we require
+        // sync adapters that don't have access to the account to get user consent.
+        // This can be noisy, therefore we will white-list sync adapters installed
+        // before we started checking for account access because they already know
+        // the account (they run before) which is the genie is out of the bottle.
+        whiteListExistingSyncAdaptersIfNeeded();
+    }
+
+    private void whiteListExistingSyncAdaptersIfNeeded() {
+        if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
+            return;
+        }
+        List<UserInfo> users = mUserManager.getUsers(true);
+        final int userCount = users.size();
+        for (int i = 0; i < userCount; i++) {
+            UserHandle userHandle = users.get(i).getUserHandle();
+            final int userId = userHandle.getIdentifier();
+            for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> service
+                    : mSyncAdapters.getAllServices(userId)) {
+                String packageName = service.componentName.getPackageName();
+                for (Account account : mAccountManager.getAccountsByTypeAsUser(
+                        service.type.accountType, userHandle)) {
+                    if (!canAccessAccount(account, packageName, userId)) {
+                        mAccountManager.updateAppPermission(account,
+                                AccountManager.ACCOUNT_ACCESS_TOKEN, service.uid, true);
+                    }
+                }
+            }
+        }
     }
 
     private boolean isDeviceProvisioned() {
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 64849aa..8289bae 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -137,7 +137,7 @@
     private static final boolean SYNC_ENABLED_DEFAULT = false;
 
     // the version of the accounts xml file format
-    private static final int ACCOUNTS_VERSION = 2;
+    private static final int ACCOUNTS_VERSION = 3;
 
     private static HashMap<String, String> sAuthorityRenames;
     private static PeriodicSyncAddedListener mPeriodicSyncAddedListener;
@@ -408,6 +408,8 @@
     private OnSyncRequestListener mSyncRequestListener;
     private OnAuthorityRemovedListener mAuthorityRemovedListener;
 
+    private boolean mGrantSyncAdaptersAccountAccess;
+
     private SyncStorageEngine(Context context, File dataDir) {
         mContext = context;
         sSyncStorageEngine = this;
@@ -1410,6 +1412,10 @@
         }
     }
 
+    public boolean shouldGrantSyncAdaptersAccountAccess() {
+        return mGrantSyncAdaptersAccountAccess;
+    }
+
     /**
      * public for testing
      */
@@ -1464,6 +1470,11 @@
                 } catch (NumberFormatException e) {
                     version = 0;
                 }
+
+                if (version < 3) {
+                    mGrantSyncAdaptersAccountAccess = true;
+                }
+
                 String nextIdString = parser.getAttributeValue(null, XML_ATTR_NEXT_AUTHORITY_ID);
                 try {
                     int id = (nextIdString == null) ? 0 : Integer.parseInt(nextIdString);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 4a042da..ef780bc 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1769,16 +1769,25 @@
     private void setUidPolicyUncheckedUL(int uid, int oldPolicy, int policy, boolean persist) {
         setUidPolicyUncheckedUL(uid, policy, persist);
 
-        final boolean isBlacklisted = policy == POLICY_REJECT_METERED_BACKGROUND;
-        mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_BLACKLIST_CHANGED, uid,
-                isBlacklisted ? 1 : 0).sendToTarget();
-
         final boolean wasBlacklisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND;
-        // Checks if app was added or removed to the blacklist.
-        if ((oldPolicy == POLICY_NONE && isBlacklisted)
-                || (wasBlacklisted && policy == POLICY_NONE)) {
-            mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 1, null)
-                    .sendToTarget();
+        final boolean isBlacklisted = policy == POLICY_REJECT_METERED_BACKGROUND;
+        final boolean wasWhitelisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND;
+        final boolean isWhitelisted = policy == POLICY_ALLOW_METERED_BACKGROUND;
+        final boolean notifyApp;
+        if (!isUidValidForWhitelistRules(uid)) {
+            notifyApp = false;
+        } else {
+            final boolean wasBlocked = wasBlacklisted || (mRestrictBackground && !wasWhitelisted);
+            final boolean isBlocked = isBlacklisted || (mRestrictBackground && !isWhitelisted);
+            notifyApp = wasBlocked != isBlocked;
+        }
+        if (isBlacklisted != wasBlacklisted) {
+            mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_BLACKLIST_CHANGED, uid,
+                    isBlacklisted ? 1 : 0, Boolean.valueOf(notifyApp)).sendToTarget();
+        }
+        if (isWhitelisted != wasWhitelisted) {
+            mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid,
+                    isWhitelisted ? 1 : 0, Boolean.valueOf(notifyApp)).sendToTarget();
         }
     }
 
@@ -2066,61 +2075,6 @@
     }
 
     /**
-     * @deprecated - should use {@link #setUidPolicy(int, int)} directly.
-     */
-    @Override
-    @Deprecated
-    public void addRestrictBackgroundWhitelistedUid(int uid) {
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        final boolean oldStatus;
-        final boolean needFirewallRules;
-        int changed;
-        synchronized (mUidRulesFirstLock) {
-            final int oldUidPolicy = mUidPolicy.get(uid, POLICY_NONE);
-            oldStatus = (oldUidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
-            if (oldStatus) {
-                if (LOGD) Slog.d(TAG, "uid " + uid + " is already whitelisted");
-                return;
-            }
-            needFirewallRules = isUidValidForWhitelistRules(uid);
-            Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
-            setUidPolicyUncheckedUL(uid, oldUidPolicy, POLICY_ALLOW_METERED_BACKGROUND, false);
-            if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
-                    && mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
-                if (LOGD) Slog.d(TAG, "Removing uid " + uid
-                        + " from revoked restrict background whitelist");
-                mRestrictBackgroundWhitelistRevokedUids.delete(uid);
-            }
-            if (needFirewallRules) {
-                // Only update firewall rules if necessary...
-                updateRulesForDataUsageRestrictionsUL(uid);
-            }
-            // ...but always persists the whitelist request.
-            synchronized (mNetworkPoliciesSecondLock) {
-                writePolicyAL();
-            }
-            changed = (mRestrictBackground && !oldStatus && needFirewallRules) ? 1 : 0;
-        }
-        mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, changed,
-                Boolean.TRUE).sendToTarget();
-    }
-
-    /**
-     * @deprecated - should use {@link #setUidPolicy(int, int)} directly.
-     */
-    @Override
-    @Deprecated
-    public void removeRestrictBackgroundWhitelistedUid(int uid) {
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        final boolean changed;
-        synchronized (mUidRulesFirstLock) {
-            changed = removeRestrictBackgroundWhitelistedUidUL(uid, false, true);
-        }
-        mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, changed ? 1 : 0,
-                Boolean.FALSE).sendToTarget();
-    }
-
-    /**
      * Removes a uid from the restricted background whitelist, returning whether its current
      * {@link ConnectivityManager.RestrictBackgroundStatus} changed.
      */
@@ -2158,43 +2112,6 @@
         return mRestrictBackground && needFirewallRules;
     }
 
-    /**
-     * @deprecated - should use {@link #getUidsWithPolicy(int)} instead, but first need to change
-     * that method to use logical OR (|).
-     */
-    @Override
-    @Deprecated
-    public int[] getRestrictBackgroundWhitelistedUids() {
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        int[] whitelist = null;
-        synchronized (mUidRulesFirstLock) {
-            // First calculate size
-            int size = 0;
-            int policySize = mUidPolicy.size();
-            for (int i = 0; i < policySize; i++) {
-                if ((mUidPolicy.valueAt(i) & POLICY_ALLOW_METERED_BACKGROUND) != 0) {
-                    size ++;
-                }
-            }
-            whitelist = new int[size];
-            // Then populate it.
-            if (size > 0) {
-                int index = 0;
-                for (int i = 0; i < policySize; i++) {
-                    final int uid = mUidPolicy.keyAt(i);
-                    if ((mUidPolicy.valueAt(i) & POLICY_ALLOW_METERED_BACKGROUND) != 0) {
-                        whitelist[index++] = uid;
-                    }
-                }
-            }
-        }
-        if (LOGV) {
-            Slog.v(TAG, "getRestrictBackgroundWhitelistedUids(): "
-                    + Arrays.toString(whitelist));
-        }
-        return whitelist;
-    }
-
     @Override
     public int getRestrictBackgroundByCaller() {
         mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
@@ -2412,20 +2329,6 @@
                     fout.decreaseIndent();
                 }
 
-                final int[] restrictBackgroundWhitelistUids =
-                        getRestrictBackgroundWhitelistedUids();
-                size = restrictBackgroundWhitelistUids.length;
-                if (size > 0) {
-                    fout.println("Restrict background whitelist uids:");
-                    fout.increaseIndent();
-                    for (int i = 0; i < size; i++) {
-                        fout.print("UID=");
-                        fout.print(restrictBackgroundWhitelistUids[i]);
-                        fout.println();
-                    }
-                    fout.decreaseIndent();
-                }
-
                 size = mDefaultRestrictBackgroundWhitelistUids.size();
                 if (size > 0) {
                     fout.println("Default restrict background whitelist uids:");
@@ -3257,52 +3160,29 @@
                     return true;
                 }
                 case MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED: {
-                    // MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED can be called in 2 occasions:
-                    // - when an app is whitelisted
-                    // - when an app is blacklisted
-                    //
-                    // Whether the internal listeners (INetworkPolicyListener implementations) or
-                    // app broadcast receivers are notified depend on the following rules:
-                    //
-                    // - App receivers are only notified when the app status changed (msg.arg2 = 1)
-                    // - Listeners are only notified when app was whitelisted (msg.obj is not null),
-                    //   since blacklist notifications are handled through MSG_RULES_CHANGED).
                     final int uid = msg.arg1;
-                    final boolean changed = msg.arg2 == 1;
-                    final Boolean whitelisted = (Boolean) msg.obj;
-
+                    final boolean whitelisted = msg.arg2 == 1;
+                    final Boolean notifyApp = (Boolean) msg.obj;
                     // First notify internal listeners...
-                    if (whitelisted != null) {
-                        final boolean whitelistedBool = whitelisted.booleanValue();
-                        dispatchRestrictBackgroundWhitelistChanged(mConnectivityListener, uid,
-                                whitelistedBool);
-                        final int length = mListeners.beginBroadcast();
-                        for (int i = 0; i < length; i++) {
-                            final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
-                            dispatchRestrictBackgroundWhitelistChanged(listener, uid,
-                                    whitelistedBool);
-                        }
-                        mListeners.finishBroadcast();
+                    dispatchRestrictBackgroundWhitelistChanged(mConnectivityListener, uid,
+                            whitelisted);
+                    final int length = mListeners.beginBroadcast();
+                    for (int i = 0; i < length; i++) {
+                        final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+                        dispatchRestrictBackgroundWhitelistChanged(listener, uid, whitelisted);
                     }
-                    final PackageManager pm = mContext.getPackageManager();
-                    final String[] packages = pm.getPackagesForUid(uid);
-                    if (changed && packages != null) {
-                        // ...then notify apps listening to ACTION_RESTRICT_BACKGROUND_CHANGED
-                        final int userId = UserHandle.getUserId(uid);
-                        for (String packageName : packages) {
-                            final Intent intent = new Intent(
-                                    ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED);
-                            intent.setPackage(packageName);
-                            intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                            mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
-                        }
+                    mListeners.finishBroadcast();
+                    // ...then apps listening to ACTION_RESTRICT_BACKGROUND_CHANGED
+                    if (notifyApp.booleanValue()) {
+                        broadcastRestrictBackgroundChanged(uid, notifyApp);
                     }
                     return true;
                 }
                 case MSG_RESTRICT_BACKGROUND_BLACKLIST_CHANGED: {
                     final int uid = msg.arg1;
                     final boolean blacklisted = msg.arg2 == 1;
-
+                    final Boolean notifyApp = (Boolean) msg.obj;
+                    // First notify internal listeners...
                     dispatchRestrictBackgroundBlacklistChanged(mConnectivityListener, uid,
                             blacklisted);
                     final int length = mListeners.beginBroadcast();
@@ -3312,6 +3192,10 @@
                                 blacklisted);
                     }
                     mListeners.finishBroadcast();
+                    // ...then apps listening to ACTION_RESTRICT_BACKGROUND_CHANGED
+                    if (notifyApp.booleanValue()) {
+                        broadcastRestrictBackgroundChanged(uid, notifyApp);
+                    }
                     return true;
                 }
                 case MSG_ADVISE_PERSIST_THRESHOLD: {
@@ -3342,8 +3226,24 @@
                 }
             }
         }
+
     };
 
+    private void broadcastRestrictBackgroundChanged(int uid, Boolean changed) {
+        final PackageManager pm = mContext.getPackageManager();
+        final String[] packages = pm.getPackagesForUid(uid);
+        if (packages != null) {
+            final int userId = UserHandle.getUserId(uid);
+            for (String packageName : packages) {
+                final Intent intent =
+                        new Intent(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED);
+                intent.setPackage(packageName);
+                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+            }
+        }
+    }
+
     private void setInterfaceQuota(String iface, long quotaBytes) {
         try {
             mNetworkManager.setInterfaceQuota(iface, quotaBytes);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index 5e68f8e..4ca69dc 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -16,9 +16,11 @@
 
 package com.android.server.net;
 
+import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.wifi.WifiInfo.removeDoubleQuotes;
+
 import static com.android.server.net.NetworkPolicyManagerService.newWifiPolicy;
 import static com.android.server.net.NetworkPolicyManagerService.TAG;
 
@@ -191,10 +193,10 @@
         return -1;
     }
 
-    private int listRestrictBackgroundWhitelist() throws RemoteException {
+    private int listUidPolicies(String msg, int policy) throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
-        final int[] uids = mInterface.getRestrictBackgroundWhitelistedUids();
-        pw.print("Restrict background whitelisted UIDs: ");
+        final int[] uids = mInterface.getUidsWithPolicy(policy);
+        pw.print(msg); pw.print(": ");
         if (uids.length == 0) {
             pw.println("none");
         } else {
@@ -208,22 +210,14 @@
         return 0;
     }
 
-    private int listRestrictBackgroundBlacklist() throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
+    private int listRestrictBackgroundWhitelist() throws RemoteException {
+        return listUidPolicies("Restrict background whitelisted UIDs",
+                POLICY_ALLOW_METERED_BACKGROUND);
+    }
 
-        final int[] uids = mInterface.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);
-        pw.print("Restrict background blacklisted UIDs: ");
-        if (uids.length == 0) {
-            pw.println("none");
-        } else {
-            for (int i = 0; i < uids.length; i++) {
-                int uid = uids[i];
-                pw.print(uid);
-                pw.print(' ');
-            }
-        }
-        pw.println();
-        return 0;
+    private int listRestrictBackgroundBlacklist() throws RemoteException {
+        return listUidPolicies("Restrict background blacklisted UIDs",
+                POLICY_REJECT_METERED_BACKGROUND);
     }
 
     private int getRestrictBackground() throws RemoteException {
@@ -242,42 +236,46 @@
         return 0;
     }
 
-    private int addRestrictBackgroundWhitelist() throws RemoteException {
-      final int uid = getUidFromNextArg();
-      if (uid < 0) {
-          return uid;
-      }
-      mInterface.addRestrictBackgroundWhitelistedUid(uid);
-      return 0;
-    }
-
-    private int removeRestrictBackgroundWhitelist() throws RemoteException {
+    private int setUidPolicy(int policy) throws RemoteException {
         final int uid = getUidFromNextArg();
         if (uid < 0) {
             return uid;
         }
-        mInterface.removeRestrictBackgroundWhitelistedUid(uid);
+        mInterface.setUidPolicy(uid, policy);
         return 0;
     }
 
-    private int addRestrictBackgroundBlacklist() throws RemoteException {
+    private int resetUidPolicy(String errorMessage, int expectedPolicy) throws RemoteException {
         final int uid = getUidFromNextArg();
         if (uid < 0) {
             return uid;
         }
-        mInterface.setUidPolicy(uid, POLICY_REJECT_METERED_BACKGROUND);
-        return 0;
-    }
-
-    private int removeRestrictBackgroundBlacklist() throws RemoteException {
-        final int uid = getUidFromNextArg();
-        if (uid < 0) {
-            return uid;
+        int actualPolicy = mInterface.getUidPolicy(uid);
+        if (actualPolicy != expectedPolicy) {
+            final PrintWriter pw = getOutPrintWriter();
+            pw.print("Error: UID "); pw.print(uid); pw.print(' '); pw.println(errorMessage);
+            return -1;
         }
         mInterface.setUidPolicy(uid, POLICY_NONE);
         return 0;
     }
 
+    private int addRestrictBackgroundWhitelist() throws RemoteException {
+        return setUidPolicy(POLICY_ALLOW_METERED_BACKGROUND);
+    }
+
+    private int removeRestrictBackgroundWhitelist() throws RemoteException {
+        return resetUidPolicy("not whitelisted", POLICY_ALLOW_METERED_BACKGROUND);
+    }
+
+    private int addRestrictBackgroundBlacklist() throws RemoteException {
+        return setUidPolicy(POLICY_REJECT_METERED_BACKGROUND);
+    }
+
+    private int removeRestrictBackgroundBlacklist() throws RemoteException {
+        return resetUidPolicy("not blacklisted", POLICY_REJECT_METERED_BACKGROUND);
+    }
+
     private int listWifiNetworks() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final String arg = getNextArg();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index cee5a46..084ba8e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -58,7 +58,6 @@
 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;
@@ -93,7 +92,6 @@
 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;
@@ -122,6 +120,8 @@
 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,6 +138,7 @@
 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;
@@ -193,7 +194,7 @@
     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
     private static final int MESSAGE_RANKING_SORT = 1001;
 
-    static final int LONG_DELAY = 3500; // 3.5 seconds
+    static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
     static final int SHORT_DELAY = 2000; // 2 seconds
 
     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
@@ -232,6 +233,7 @@
     @Nullable StatusBarManagerInternal mStatusBar;
     Vibrator mVibrator;
     private VrManagerInternal mVrManagerInternal;
+    private WindowManagerInternal mWindowManagerInternal;
 
     final IBinder mForegroundToken = new Binder();
     private Handler mHandler;
@@ -452,13 +454,15 @@
         final String pkg;
         final ITransientNotification callback;
         int duration;
+        Binder token;
 
-        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
-        {
+        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
+                    Binder token) {
             this.pid = pid;
             this.pkg = pkg;
             this.callback = callback;
             this.duration = duration;
+            this.token = token;
         }
 
         void update(int duration) {
@@ -1125,6 +1129,7 @@
             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
@@ -1325,10 +1330,13 @@
                             }
                         }
 
-                        record = new ToastRecord(callingPid, pkg, callback, duration);
+                        Binder token = new Binder();
+                        mWindowManagerInternal.addWindowToken(token,
+                                WindowManager.LayoutParams.TYPE_TOAST);
+                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
                         mToastQueue.add(record);
                         index = mToastQueue.size() - 1;
-                        keepProcessAliveLocked(callingPid);
+                        keepProcessAliveIfNeededLocked(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.
@@ -2991,7 +2999,7 @@
         while (record != null) {
             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
             try {
-                record.callback.show();
+                record.callback.show(record.token);
                 scheduleTimeoutLocked(record);
                 return;
             } catch (RemoteException e) {
@@ -3002,7 +3010,7 @@
                 if (index >= 0) {
                     mToastQueue.remove(index);
                 }
-                keepProcessAliveLocked(record.pid);
+                keepProcessAliveIfNeededLocked(record.pid);
                 if (mToastQueue.size() > 0) {
                     record = mToastQueue.get(0);
                 } else {
@@ -3022,8 +3030,11 @@
             // don't worry about this, we're about to remove it from
             // the list anyway
         }
-        mToastQueue.remove(index);
-        keepProcessAliveLocked(record.pid);
+
+        ToastRecord lastToast = mToastQueue.remove(index);
+        mWindowManagerInternal.removeWindowToken(lastToast.token, true);
+
+        keepProcessAliveIfNeededLocked(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
@@ -3067,7 +3078,7 @@
     }
 
     // lock on mToastQueue
-    void keepProcessAliveLocked(int pid)
+    void keepProcessAliveIfNeededLocked(int pid)
     {
         int toastCount = 0; // toasts from this pid
         ArrayList<ToastRecord> list = mToastQueue;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 19b1201..1ef4a9f 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -176,6 +176,16 @@
             isProfileGuidedFilter = false;
         }
 
+        // Disable profile guided compilation for vmSafeMode.
+        final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE)
+                != 0;
+        final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE)
+                != 0;
+        if (vmSafeMode) {
+            targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter);
+            isProfileGuidedFilter = false;
+        }
+
         // If we're asked to take profile updates into account, check now.
         boolean newProfile = false;
         if (checkProfiles && isProfileGuidedFilter) {
@@ -187,9 +197,6 @@
             }
         }
 
-        final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
-        final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-
         boolean performedDexOpt = false;
         boolean successfulDexOpt = true;
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 48b3a54..d98539e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -539,6 +539,9 @@
     final boolean mIsPreNUpgrade;
     final boolean mIsPreNMR1Upgrade;
 
+    @GuardedBy("mPackages")
+    private boolean mDexOptDialogShown;
+
     /** The location for ASEC container files on internal storage. */
     final String mAsecInternalPath;
 
@@ -7176,7 +7179,11 @@
                     }
                 }
                 if (doTrim) {
-                    if (!isFirstBoot()) {
+                    final boolean dexOptDialogShown;
+                    synchronized (mPackages) {
+                        dexOptDialogShown = mDexOptDialogShown;
+                    }
+                    if (!isFirstBoot() && dexOptDialogShown) {
                         try {
                             ActivityManagerNative.getDefault().showBootMessage(
                                     mContext.getResources().getString(
@@ -7270,6 +7277,22 @@
                                     numberOfPackagesVisited, numberOfPackagesToDexopt), true);
                 } catch (RemoteException e) {
                 }
+                synchronized (mPackages) {
+                    mDexOptDialogShown = true;
+                }
+            }
+
+            // If the OTA updates a system app which was previously preopted to a non-preopted state
+            // the app might end up being verified at runtime. That's because by default the apps
+            // are verify-profile but for preopted apps there's no profile.
+            // Do a hacky check to ensure that if we have no profiles (a reasonable indication
+            // that before the OTA the app was preopted) the app gets compiled with a non-profile
+            // filter (by default interpret-only).
+            // Note that at this stage unused apps are already filtered.
+            if (isSystemApp(pkg) &&
+                    DexFile.isProfileGuidedCompilerFilter(compilerFilter) &&
+                    !Environment.getReferenceProfile(pkg.packageName).exists()) {
+                compilerFilter = getNonProfileGuidedCompilerFilter(compilerFilter);
             }
 
             // If the OTA updates a system app which was previously preopted to a non-preopted state
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f74febe..cfec1ba 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -306,6 +306,9 @@
     /** 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
@@ -2310,9 +2313,22 @@
                     attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
                 }
                 break;
+
             case TYPE_SCREENSHOT:
                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                 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) {
@@ -2886,7 +2902,11 @@
             if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
                 if (transit == TRANSIT_EXIT
                         || transit == TRANSIT_HIDE) {
-                    return R.anim.dock_bottom_exit;
+                    if (isKeyguardShowingAndNotOccluded()) {
+                        return R.anim.dock_bottom_exit_keyguard;
+                    } else {
+                        return R.anim.dock_bottom_exit;
+                    }
                 } else if (transit == TRANSIT_ENTER
                         || transit == TRANSIT_SHOW) {
                     return R.anim.dock_bottom_enter;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 518b9b5..47b5f3d 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -75,6 +75,7 @@
     final boolean voiceInteraction;
 
     Task mTask;
+    // TODO: Have a fillParent variable in WindowContainer to this?
     boolean appFullscreen;
     int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     boolean layoutConfigChanges;
@@ -100,7 +101,7 @@
     // These are to track the app's real drawing status if there were no saved surfaces.
     boolean allDrawnExcludingSaved;
     int numInterestingWindowsExcludingSaved;
-    int numDrawnWindowsExclusingSaved;
+    int numDrawnWindowsExcludingSaved;
 
     // Is this window's surface needed?  This is almost like hidden, except
     // it will sometimes be true a little earlier: when the token has
@@ -133,6 +134,7 @@
     // Input application handle used by the input dispatcher.
     final InputApplicationHandle mInputApplicationHandle;
 
+    // TODO: Have a WindowContainer state for tracking exiting/deferred removal.
     boolean mIsExiting;
 
     boolean mLaunchTaskBehind;
@@ -356,18 +358,12 @@
         return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
     }
 
-    void removeAppFromTaskLocked() {
+    @Override
+    void removeIfPossible() {
         mIsExiting = false;
         removeAllWindows();
-
-        // Use local variable because removeAppToken will null out mTask.
-        final Task task = mTask;
-        if (task != null) {
-            if (!task.removeAppToken(this)) {
-                Slog.e(TAG, "removeAppFromTaskLocked: token=" + this
-                        + " not found.");
-            }
-            task.mStack.mExitingAppTokens.remove(this);
+        if (mTask != null) {
+            mTask.detachChild(this);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 990405a..e7a6747 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -22,6 +22,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
@@ -514,7 +515,7 @@
                     for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
                         AppWindowToken wtoken = tokens.get(tokenNdx);
                         if (wtoken.mIsExiting) {
-                            wtoken.removeAppFromTaskLocked();
+                            wtoken.removeIfPossible();
                         }
                     }
                 }
@@ -679,4 +680,39 @@
             mStacks.get(i).overridePlayingAppAnimations(a);
         }
     }
+
+    boolean canAddToastWindowForUid(int uid) {
+        // We allow one toast window per UID being shown at a time.
+        WindowList windows = 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 && !window.mAnimatingExit) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus,
+                                                   WindowState newFocus) {
+        if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) {
+            return;
+        }
+        final int lostFocusUid = oldFocus.mOwnerUid;
+        WindowList windows = 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 (!mService.mH.hasMessages(WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window)) {
+                    mService.mH.sendMessageDelayed(
+                            mService.mH.obtainMessage(
+                                    WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window),
+                            window.mAttrs.hideTimeoutMilliseconds);
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4241b32..754a9a6 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -179,6 +179,14 @@
         }
     }
 
+    // TODO: Don't forget to switch to WC.detachChild
+    void detachChild(AppWindowToken wtoken) {
+        if (!removeAppToken(wtoken)) {
+            Slog.e(TAG, "detachChild: token=" + this + " not found.");
+        }
+        mStack.mExitingAppTokens.remove(wtoken);
+    }
+
     boolean removeAppToken(AppWindowToken wtoken) {
         boolean removed = mAppTokens.remove(wtoken);
         if (mAppTokens.size() == 0) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index fd6994c..d37d0e1 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -67,17 +67,50 @@
         mChildren.add(child);
     }
 
-    /** Removes this window container and its children */
+    /**
+     * Removes this window container and its children with no regard for what else might be going on
+     * in the system. For example, the container will be removed during animation if this method is
+     * called which isn't desirable. For most cases you want to call {@link #removeIfPossible()}
+     * which allows the system to defer removal until a suitable time.
+     */
     @CallSuper
-    void remove() {
+    void removeImmediately() {
         while (!mChildren.isEmpty()) {
-            final WindowContainer child = mChildren.removeLast();
-            child.remove();
+            final WindowContainer child = mChildren.peekLast();
+            child.removeImmediately();
+            // Need to do this after calling remove on the child because the child might try to
+            // remove/detach itself from its parent which will cause an exception if we remove
+            // it before calling remove on the child.
+            mChildren.remove(child);
         }
 
         if (mParent != null) {
-            mParent.mChildren.remove(this);
-            mParent = null;
+            mParent.detachChild(this);
+        }
+    }
+
+    /**
+     * Removes this window container and its children taking care not to remove them during a
+     * critical stage in the system. For example, some containers will not be removed during
+     * animation if this method is called.
+     */
+    // TODO: figure-out implementation that works best for this.
+    // E.g. when do we remove from parent list? maybe not...
+    void removeIfPossible() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.removeIfPossible();
+        }
+    }
+
+    /** Detaches the input child container from this container which is its parent. */
+    @CallSuper
+    void detachChild(WindowContainer child) {
+        if (mChildren.remove(child)) {
+            child.mParent = null;
+        } else {
+            throw new IllegalArgumentException("detachChild: container=" + child
+                    + " is not a child of container=" + this);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 856e101..5c681d5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -35,6 +35,7 @@
 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;
@@ -200,6 +201,7 @@
 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;
@@ -247,7 +249,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
-import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
@@ -1475,6 +1476,7 @@
         boolean reportNewConfig = false;
         WindowState parentWindow = null;
         long origId;
+        final int callingUid = Binder.getCallingUid();
         final int type = attrs.type;
 
         synchronized(mWindowMap) {
@@ -1527,6 +1529,9 @@
             // If this is a child window, we want to apply the same type checking rules as the
             // parent window type.
             final int rootType = hasParent ? parentWindow.mAttrs.type : type;
+
+            boolean addToastWindowRequiresToken = false;
+
             if (token == null) {
                 if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                     Slog.w(TAG_WM, "Attempted to add application window with unknown token "
@@ -1563,6 +1568,15 @@
                             + 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,
+                            parentWindow)) {
+                        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);
             } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                 atoken = token.asAppWindowToken();
@@ -1611,7 +1625,16 @@
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-            } else if (rootType == TYPE_QS_DIALOG) {
+            } else if (type == TYPE_TOAST) {
+                // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
+                addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
+                        callingUid, parentWindow);
+                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 "
                             + attrs.token + ".  Aborting.");
@@ -1654,6 +1677,36 @@
                 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 (!getDefaultDisplayContentLocked().canAddToastWindowForUid(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;
@@ -1786,11 +1839,6 @@
             if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
                 reportNewConfig = true;
             }
-            if (attrs.removeTimeoutMilliseconds > 0) {
-                mH.sendMessageDelayed(
-                        mH.obtainMessage(H.WINDOW_REMOVE_TIMEOUT, win),
-                        attrs.removeTimeoutMilliseconds);
-            }
         }
 
         if (reportNewConfig) {
@@ -1802,6 +1850,32 @@
         return res;
     }
 
+    private boolean doesAddToastWindowRequireToken(String packageName, int callingUid,
+            WindowState attachedWindow) {
+        // Try using the target SDK of the root window
+        if (attachedWindow != null) {
+            return attachedWindow.mAppToken != null
+                    && attachedWindow.mAppToken.targetSdk > Build.VERSION_CODES.N_MR1;
+        } 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;
+    }
+
     /**
      * Returns true if we're done setting up any transitions.
      */
@@ -1896,7 +1970,10 @@
 
     /**
      * Performs some centralized bookkeeping clean-up on the window that is being removed.
-     * NOTE: Should only be called from {@link WindowState#remove()}
+     * NOTE: Should only be called from {@link WindowState#removeImmediately()}
+     * TODO: Maybe better handled with a method {@link WindowContainer#detachChild} if we can
+     * figure-out a good way to have all parents of a WindowState doing the same thing without
+     * forgetting to add the wiring when a new parent of WindowState is added.
      */
     void postWindowRemoveCleanupLocked(WindowState win) {
         if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "postWindowRemoveCleanupLocked: " + win);
@@ -3756,7 +3833,7 @@
                     // soon as their animations are complete
                     wtoken.mAppAnimator.clearAnimation();
                     wtoken.mAppAnimator.animating = false;
-                    wtoken.removeAppFromTaskLocked();
+                    wtoken.removeIfPossible();
                 }
 
                 wtoken.removed = true;
@@ -7078,7 +7155,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_REMOVE_TIMEOUT = 52;
+        public static final int WINDOW_HIDE_TIMEOUT = 52;
         public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
         public static final int RESTORE_POINTER_ICON = 55;
@@ -7705,7 +7782,7 @@
                     mAmInternal.notifyStartingWindowDrawn();
                 }
                 break;
-                case WINDOW_REMOVE_TIMEOUT: {
+                case WINDOW_HIDE_TIMEOUT: {
                     final WindowState window = (WindowState) msg.obj;
                     synchronized(mWindowMap) {
                         // TODO: This is all about fixing b/21693547
@@ -7716,8 +7793,11 @@
                         // 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.
+                        // 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.
                         window.mAttrs.flags &= ~FLAG_KEEP_SCREEN_ON;
+                        window.hidePermanentlyLw();
                         window.setDisplayLayoutNeeded();
                         mWindowPlacerLocked.performSurfacePlacement();
                     }
@@ -8752,6 +8832,12 @@
 
             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.
+            getDefaultDisplayContentLocked().scheduleToastWindowsTimeoutIfNeededLocked(
+                        oldFocus, newFocus);
+
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
             return true;
         }
@@ -10449,7 +10535,7 @@
         public void removeWindowToken(IBinder token, boolean removeWindows) {
             synchronized(mWindowMap) {
                 if (removeWindows) {
-                    WindowToken wtoken = mTokenMap.remove(token);
+                    final WindowToken wtoken = mTokenMap.remove(token);
                     if (wtoken != null) {
                         wtoken.removeAllWindows();
                     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 2c359fc..fd47f5b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -187,9 +187,20 @@
     boolean mEnforceSizeCompat;
     int mViewVisibility;
     int mSystemUiVisibility;
+    /**
+     * The visibility of the window based on policy like {@link WindowManagerPolicy}.
+     * Normally set by calling {@link #showLw} and {@link #hideLw}.
+     */
     boolean mPolicyVisibility = true;
+    /**
+     * What {@link #mPolicyVisibility} should be set to after a transition animation.
+     * For example, {@link #mPolicyVisibility} might true during an exit animation to hide it and
+     * then set to the value of {@link #mPolicyVisibilityAfterAnim} which is false after the exit
+     * animation is done.
+     */
     boolean mPolicyVisibilityAfterAnim = true;
     boolean mAppOpVisibility = true;
+    boolean mPermanentlyHidden; // the window should never be shown again
     boolean mAppFreezing;
     boolean mHidden;    // Used to determine if to show child windows.
     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
@@ -1404,8 +1415,7 @@
     @Override
     public boolean isDrawnLw() {
         return mHasSurface && !mDestroying &&
-                (mWinAnimator.mDrawState == READY_TO_SHOW
-                || mWinAnimator.mDrawState == HAS_DRAWN);
+                (mWinAnimator.mDrawState == READY_TO_SHOW || mWinAnimator.mDrawState == HAS_DRAWN);
     }
 
     /**
@@ -1594,12 +1604,12 @@
     void onWindowReplacementTimeout() {
         if (mWillReplaceWindow) {
             // Since the window already timed out, remove it immediately now.
-            // Use WindowState#remove() instead of WindowState#removeIfPossible(), as the latter
+            // Use WindowState#removeImmediately() instead of WindowState#removeIfPossible(), as the latter
             // delays removal on certain conditions, which will leave the stale window in the
             // stack and marked mWillReplaceWindow=false, so the window will never be removed.
             //
             // Also removes child windows.
-            remove();
+            removeImmediately();
         } else {
             for (int i = mChildren.size() - 1; i >= 0; --i) {
                 final WindowState c = (WindowState) mChildren.get(i);
@@ -1618,12 +1628,13 @@
     }
 
     @Override
-    void remove() {
-        super.remove();
+    void removeImmediately() {
+        super.removeImmediately();
 
         if (mRemoved) {
             // Nothing to do.
-            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "WS.remove: " + this + " Already removed...");
+            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                    "WS.removeImmediately: " + this + " Already removed...");
             return;
         }
 
@@ -1660,15 +1671,13 @@
         mService.postWindowRemoveCleanupLocked(this);
     }
 
+    @Override
     void removeIfPossible() {
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowState c = (WindowState) mChildren.get(i);
-            c.removeIfPossible(false /*keepVisibleDeadWindow*/);
-        }
+        super.removeIfPossible();
         removeIfPossible(false /*keepVisibleDeadWindow*/);
     }
 
-    void removeIfPossible(boolean keepVisibleDeadWindow) {
+    private void removeIfPossible(boolean keepVisibleDeadWindow) {
         mWindowRemovalAllowed = true;
         if (DEBUG_ADD_REMOVE) Slog.v(TAG,
                 "removeIfPossible: " + this + " callers=" + Debug.getCallers(5));
@@ -1793,7 +1802,7 @@
             }
         }
 
-        remove();
+        removeImmediately();
         // Removing a visible window will effect the computed orientation
         // So just update orientation if needed.
         if (wasVisible && mService.updateOrientationFromAppTokensLocked(false)) {
@@ -2010,7 +2019,7 @@
         mReplacingRemoveRequested = false;
         mReplacementWindow = null;
         if (mAnimatingExit || !mAnimateReplacingWindow) {
-            remove();
+            removeImmediately();
         }
     }
 
@@ -2249,6 +2258,11 @@
             // 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;
@@ -2336,6 +2350,13 @@
         }
     }
 
+    public void hidePermanentlyLw() {
+        if (!mPermanentlyHidden) {
+            mPermanentlyHidden = true;
+            hideLw(true, true);
+        }
+    }
+
     public void pokeDrawLockLw(long timeout) {
         if (isVisibleOrAdding()) {
             if (mDrawLock == null) {
@@ -2567,7 +2588,7 @@
                     destroyOrSaveSurface();
                 }
                 if (mRemoveOnExit) {
-                    remove();
+                    removeImmediately();
                 }
                 if (cleanupOnResume) {
                     requestUpdateWallpaperIfNeeded();
@@ -3175,7 +3196,7 @@
             pw.println(Integer.toHexString(mSystemUiVisibility));
         }
         if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
-                || isParentWindowHidden()) {
+                || isParentWindowHidden()|| mPermanentlyHidden) {
             pw.print(prefix); pw.print("mPolicyVisibility=");
                     pw.print(mPolicyVisibility);
                     pw.print(" mPolicyVisibilityAfterAnim=");
@@ -3183,6 +3204,7 @@
                     pw.print(" mAppOpVisibility=");
                     pw.print(mAppOpVisibility);
                     pw.print(" parentHidden="); pw.println(isParentWindowHidden());
+                    pw.print(" mPermanentlyHidden="); pw.println(mPermanentlyHidden);
         }
         if (!mRelayoutCalled || mLayoutNeeded) {
             pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index d0c73d3..317bb35 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -215,7 +215,7 @@
             while (!mService.mForceRemoves.isEmpty()) {
                 final WindowState ws = mService.mForceRemoves.remove(0);
                 Slog.i(TAG, "Force removing: " + ws);
-                ws.remove();
+                ws.removeImmediately();
             }
             Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
             Object tmp = new Object();
@@ -461,7 +461,7 @@
                     token.mAppAnimator.animating = false;
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "performLayout: App token exiting now removed" + token);
-                    token.removeAppFromTaskLocked();
+                    token.removeIfPossible();
                 }
             }
         }
@@ -545,7 +545,7 @@
             DisplayContentList displayList = new DisplayContentList();
             for (i = 0; i < N; i++) {
                 final WindowState w = mService.mPendingRemoveTmp[i];
-                w.remove();
+                w.removeImmediately();
                 final DisplayContent displayContent = w.getDisplayContent();
                 if (displayContent != null && !displayList.contains(displayContent)) {
                     displayList.add(displayContent);
@@ -797,7 +797,7 @@
                         atoken.lastTransactionSequence = mService.mTransactionSequence;
                         atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
                         atoken.numInterestingWindowsExcludingSaved = 0;
-                        atoken.numDrawnWindowsExclusingSaved = 0;
+                        atoken.numDrawnWindowsExcludingSaved = 0;
                         atoken.startingDisplayed = false;
                     }
                     if (!atoken.allDrawn && w.mightAffectAllDrawn(false /* visibleOnly */)) {
@@ -840,7 +840,7 @@
                         if (w != atoken.startingWindow && w.isInteresting()) {
                             atoken.numInterestingWindowsExcludingSaved++;
                             if (w.isDrawnLw() && !w.isAnimatingWithSavedSurface()) {
-                                atoken.numDrawnWindowsExclusingSaved++;
+                                atoken.numDrawnWindowsExcludingSaved++;
                                 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION)
                                     Slog.v(TAG, "tokenMayBeDrawnExcludingSaved: " + atoken
                                             + " w=" + w + " numInteresting="
@@ -1550,11 +1550,11 @@
                     if (!wtoken.allDrawnExcludingSaved) {
                         int numInteresting = wtoken.numInterestingWindowsExcludingSaved;
                         if (numInteresting > 0
-                                && wtoken.numDrawnWindowsExclusingSaved >= numInteresting) {
+                                && wtoken.numDrawnWindowsExcludingSaved >= numInteresting) {
                             if (DEBUG_VISIBILITY)
                                 Slog.v(TAG, "allDrawnExcludingSaved: " + wtoken
                                     + " interesting=" + numInteresting
-                                    + " drawn=" + wtoken.numDrawnWindowsExclusingSaved);
+                                    + " drawn=" + wtoken.numDrawnWindowsExcludingSaved);
                             wtoken.allDrawnExcludingSaved = true;
                             displayContent.layoutNeeded = true;
                             if (wtoken.isAnimatingInvisibleWithSavedSurface()
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 92d4c46..f3919fd 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -339,13 +339,17 @@
     }
 
     private void addRestrictBackgroundWhitelist(boolean expectIntent) throws Exception {
-        assertWhitelistUids(); // Sanity check.
+        // Sanity checks.
+        assertWhitelistUids();
+        assertUidPolicy(UID_A, POLICY_NONE);
+
         final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
         mPolicyListener.expect().onRestrictBackgroundWhitelistChanged(anyInt(), anyBoolean());
 
-        mService.addRestrictBackgroundWhitelistedUid(UID_A);
+        mService.setUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND);
 
         assertWhitelistUids(UID_A);
+        assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND);
         mPolicyListener.waitAndVerify().onRestrictBackgroundWhitelistChanged(APP_ID_A, true);
         mPolicyListener.verifyNotCalled().onRestrictBackgroundBlacklistChanged(APP_ID_A, true);
         if (expectIntent) {
@@ -376,13 +380,17 @@
     }
 
     private void removeRestrictBackgroundWhitelist(boolean expectIntent) throws Exception {
-        assertWhitelistUids(UID_A); // Sanity check.
+        // Sanity checks.
+        assertWhitelistUids(UID_A);
+        assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND);
+
         final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
         mPolicyListener.expect().onRestrictBackgroundWhitelistChanged(anyInt(), anyBoolean());
 
-        mService.removeRestrictBackgroundWhitelistedUid(UID_A);
+        mService.setUidPolicy(UID_A, POLICY_NONE);
 
         assertWhitelistUids();
+        assertUidPolicy(UID_A, POLICY_NONE);
         mPolicyListener.waitAndVerify().onRestrictBackgroundWhitelistChanged(APP_ID_A, false);
         mPolicyListener.verifyNotCalled().onRestrictBackgroundBlacklistChanged(APP_ID_A, false);
         if (expectIntent) {
@@ -393,13 +401,13 @@
     }
 
     /**
-     * Adds blacklist when restrict background is on - app should receive an intent.
+     * Adds blacklist when restrict background is on - app should not receive an intent.
      */
     @Test
     @NetPolicyXml("restrict-background-on.xml")
     public void testAddRestrictBackgroundBlacklist_restrictBackgroundOn() throws Exception {
         assertRestrictBackgroundOn(); // Sanity check.
-        addRestrictBackgroundBlacklist(true);
+        addRestrictBackgroundBlacklist(false);
     }
 
     /**
@@ -429,13 +437,13 @@
     }
 
     /**
-     * Removes blacklist when restrict background is on - app should receive an intent.
+     * Removes blacklist when restrict background is on - app should not receive an intent.
      */
     @Test
     @NetPolicyXml("uidA-blacklisted-restrict-background-on.xml")
     public void testRemoveRestrictBackgroundBlacklist_restrictBackgroundOn() throws Exception {
         assertRestrictBackgroundOn(); // Sanity check.
-        removeRestrictBackgroundBlacklist(true);
+        removeRestrictBackgroundBlacklist(false);
     }
 
     /**
@@ -490,6 +498,18 @@
     }
 
     @Test
+    @NetPolicyXml("uidA-whitelisted-restrict-background-on.xml")
+    public void testWhitelistedAppIsNotifiedWhenBlacklisted() throws Exception {
+        // Sanity checks.
+        assertRestrictBackgroundOn();
+        assertWhitelistUids(UID_A);
+
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+        assertRestrictBackgroundChangedReceived(futureIntent, PKG_NAME_A);
+    }
+
+    @Test
     @NetPolicyXml("restrict-background-lists-whitelist-format.xml")
     public void testRestrictBackgroundLists_whitelistFormat() throws Exception {
         restrictBackgroundListsTest();
@@ -516,12 +536,12 @@
         assertUidPolicy(UID_F, 2); // POLICY_ALLOW_BACKGROUND_BATTERY_SAVE
 
         // Remove whitelist.
-        mService.removeRestrictBackgroundWhitelistedUid(UID_A);
+        mService.setUidPolicy(UID_A, POLICY_NONE);
         assertUidPolicy(UID_A, POLICY_NONE);
         assertWhitelistUids(UID_B, UID_C);
 
         // Add whitelist when blacklisted.
-        mService.addRestrictBackgroundWhitelistedUid(UID_E);
+        mService.setUidPolicy(UID_E, POLICY_ALLOW_METERED_BACKGROUND);
         assertUidPolicy(UID_E, POLICY_ALLOW_METERED_BACKGROUND);
         assertWhitelistUids(UID_B, UID_C, UID_E);
 
@@ -539,7 +559,7 @@
     public void testRestrictBackgroundLists_mixedFormat() throws Exception {
         assertWhitelistUids(UID_A, UID_C, UID_D);
         assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND);
-        assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND);
+        assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); // Blacklist prevails.
         assertUidPolicy(UID_C, (POLICY_ALLOW_METERED_BACKGROUND | 2));
         assertUidPolicy(UID_D, POLICY_ALLOW_METERED_BACKGROUND);
     }
@@ -1054,7 +1074,7 @@
     }
 
     private void assertWhitelistUids(int... uids) {
-        assertContainsInAnyOrder(mService.getRestrictBackgroundWhitelistedUids(), uids);
+        assertContainsInAnyOrder(mService.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND), uids);
     }
 
     private void assertRestrictBackgroundOn() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
index 984a484..7571f79 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
@@ -16,19 +16,36 @@
 
 package com.android.server.am;
 
+import android.app.ActivityManager;
+import android.content.ContentResolver;
+import android.content.pm.ActivityInfo;
 import android.content.pm.UserInfo;
 import android.os.Environment;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.test.AndroidTestCase;
 import android.util.Log;
 import android.util.SparseBooleanArray;
+import android.util.Xml;
 
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
 import com.android.server.am.TaskPersister;
 
 import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
 import java.util.Random;
 
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 public class TaskPersisterTest extends AndroidTestCase {
     private static final String TEST_USER_NAME = "AM-Test-User";
 
@@ -69,6 +86,140 @@
                 taskIdsOnFile.equals(newTaskIdsOnFile));
     }
 
+    public void testActiveTimeMigration() {
+        // Simulate a migration scenario by setting the last write uptime to zero
+        ContentResolver cr = getContext().getContentResolver();
+        Settings.Secure.putLong(cr,
+                Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, 0);
+
+        // Create a dummy task record with an absolute time 1s before now
+        long pastOffset = 1000;
+        long activeTime = System.currentTimeMillis() - pastOffset;
+        TaskRecord tr0 = createDummyTaskRecordWithActiveTime(activeTime, activeTime);
+
+        // Save and load the tasks with no last persist uptime (0)
+        String tr0XmlStr = serializeTaskRecordToXmlString(tr0);
+        TaskRecord xtr0 = unserializeTaskRecordFromXmlString(tr0XmlStr, 0);
+
+        // Ensure that the absolute time has been migrated to be relative to the current elapsed
+        // time
+        assertTrue("Expected firstActiveTime to be migrated from: " + tr0.firstActiveTime +
+                " instead found: " + xtr0.firstActiveTime,
+                        xtr0.firstActiveTime <= -pastOffset);
+        assertTrue("Expected lastActiveTime to be migrated from: " + tr0.lastActiveTime +
+                " instead found: " + xtr0.lastActiveTime,
+                        xtr0.lastActiveTime <= -pastOffset);
+
+        // Ensure that the last active uptime is not set so that SystemUI can migrate it itself
+        // assuming that the last persist time is zero
+        Settings.Secure.putLongForUser(cr,
+                Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, 0, testUserId);
+        mTaskPersister.restoreTasksForUserLocked(testUserId);
+        long lastVisTaskActiveTime = Settings.Secure.getLongForUser(cr,
+                Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, -1, testUserId);
+        assertTrue("Expected last visible task active time is zero", lastVisTaskActiveTime == 0);
+    }
+
+    public void testActiveTimeOffsets() {
+        // Simulate a normal boot scenario by setting the last write uptime
+        long lastWritePastOffset = 1000;
+        long lastVisActivePastOffset = 500;
+        ContentResolver cr = getContext().getContentResolver();
+        Settings.Secure.putLong(cr,
+                Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, lastWritePastOffset);
+
+        // Create a dummy task record with an absolute time 1s before now
+        long activeTime = 250;
+        TaskRecord tr0 = createDummyTaskRecordWithActiveTime(activeTime, activeTime);
+
+        // Save and load the tasks with the last persist time
+        String tr0XmlStr = serializeTaskRecordToXmlString(tr0);
+        TaskRecord xtr0 = unserializeTaskRecordFromXmlString(tr0XmlStr, lastWritePastOffset);
+
+        // Ensure that the prior elapsed time has been offset to be relative to the current boot
+        // time
+        assertTrue("Expected firstActiveTime to be offset from: " + tr0.firstActiveTime +
+                " instead found: " + xtr0.firstActiveTime,
+                        xtr0.firstActiveTime <= (-lastWritePastOffset + activeTime));
+        assertTrue("Expected lastActiveTime to be offset from: " + tr0.lastActiveTime +
+                " instead found: " + xtr0.lastActiveTime,
+                        xtr0.lastActiveTime <= (-lastWritePastOffset + activeTime));
+
+        // Ensure that we update the last active uptime as well by simulating a restoreTasks call
+        Settings.Secure.putLongForUser(cr,
+                Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, lastVisActivePastOffset,
+                        testUserId);
+        mTaskPersister.restoreTasksForUserLocked(testUserId);
+        long lastVisTaskActiveTime = Settings.Secure.getLongForUser(cr,
+                Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, Long.MAX_VALUE,
+                        testUserId);
+        assertTrue("Expected last visible task active time to be offset", lastVisTaskActiveTime <=
+                (-lastWritePastOffset + lastVisActivePastOffset));
+    }
+
+    private TaskRecord createDummyTaskRecordWithActiveTime(long firstActiveTime,
+            long lastActiveTime) {
+        ActivityInfo info = createDummyActivityInfo();
+        ActivityManager.TaskDescription td = new ActivityManager.TaskDescription();
+        TaskRecord t = new TaskRecord(null, 0, info, null, td, null);
+        t.firstActiveTime = firstActiveTime;
+        t.lastActiveTime = lastActiveTime;
+        return t;
+    }
+
+    private ActivityInfo createDummyActivityInfo() {
+        ActivityInfo info = new ActivityInfo();
+        info.applicationInfo = getContext().getApplicationInfo();
+        return info;
+    }
+
+    private String serializeTaskRecordToXmlString(TaskRecord tr) {
+        StringWriter stringWriter = new StringWriter();
+
+        try {
+            final XmlSerializer xmlSerializer = new FastXmlSerializer();
+            xmlSerializer.setOutput(stringWriter);
+
+            xmlSerializer.startDocument(null, true);
+            xmlSerializer.startTag(null, TaskPersister.TAG_TASK);
+            tr.saveToXml(xmlSerializer);
+            xmlSerializer.endTag(null, TaskPersister.TAG_TASK);
+            xmlSerializer.endDocument();
+            xmlSerializer.flush();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return stringWriter.toString();
+    }
+
+    private TaskRecord unserializeTaskRecordFromXmlString(String xmlStr, long lastPersistUptime) {
+        StringReader reader = null;
+        TaskRecord task = null;
+        try {
+            reader = new StringReader(xmlStr);
+            final XmlPullParser in = Xml.newPullParser();
+            in.setInput(reader);
+
+            int event;
+            while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
+                    event != XmlPullParser.END_TAG) {
+                final String name = in.getName();
+                if (event == XmlPullParser.START_TAG) {
+                    if (TaskPersister.TAG_TASK.equals(name)) {
+                        task = TaskRecord.restoreFromXml(in, null, null, lastPersistUptime);
+                    }
+                }
+                XmlUtils.skipCurrentTag(in);
+            }
+        } catch (Exception e) {
+            return null;
+        } finally {
+            IoUtils.closeQuietly(reader);
+        }
+        return task;
+    }
+
     private int createUser(String name, int flags) {
         UserInfo user = mUserManager.createUser(name, flags);
         if (user == null) {
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 3341a3a..7f171fb 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 import android.util.Base64;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
 
 import android.webkit.WebViewFactory;
 import android.webkit.WebViewProviderInfo;
@@ -39,7 +40,12 @@
 
 /**
  * Tests for WebViewUpdateService
+ runtest --path frameworks/base/services/tests/servicestests/ \
+     -c com.android.server.webkit.WebViewUpdateServiceTest
  */
+// Use MediumTest instead of SmallTest as the implementation of WebViewUpdateService
+// is intended to work on several threads and uses at least one sleep/wait-statement.
+@MediumTest
 public class WebViewUpdateServiceTest extends AndroidTestCase {
     private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName();
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 4050795..32fd43a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -16,17 +16,23 @@
 
 package com.android.server.wm;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import android.content.Context;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.IWindow;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 /**
  * Tests for the {@link WindowState} class.
@@ -36,15 +42,16 @@
  * Run: adb shell am instrument -w -e class com.android.server.wm.AppWindowTokenTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
  */
 @SmallTest
-public class AppWindowTokenTests extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AppWindowTokenTests {
 
     private static WindowManagerService sWm = null;
     private final WindowManagerPolicy mPolicy = new TestWindowManagerPolicy();
     private final IWindow mIWindow = new TestIWindow();
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        final Context context = getContext();
+        final Context context = InstrumentationRegistry.getTargetContext();
         if (sWm == null) {
             // We only want to do this once for the test process as we don't want WM to try to
             // register a bunch of local services again.
@@ -52,6 +59,7 @@
         }
     }
 
+    @Test
     public void testFindMainWindow() throws Exception {
         final TestAppWindowToken token = new TestAppWindowToken();
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index ea8b7bb..a15b74b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -16,12 +16,21 @@
 
 package com.android.server.wm;
 
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
 import java.util.Comparator;
 import java.util.LinkedList;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 /**
  * Test class for {@link WindowContainer}.
  *
@@ -30,14 +39,17 @@
  * Run: adb shell am instrument -w -e class com.android.server.wm.WindowContainerTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
  */
 @SmallTest
-public class WindowContainerTests extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class WindowContainerTests {
 
+    @Test
     public void testCreation() throws Exception {
         final TestWindowContainer w = new TestWindowContainerBuilder().setLayer(0).build();
         assertNull("window must have no parent", w.getParentWindow());
         assertEquals("window must have no children", 0, w.getChildrenCount());
     }
 
+    @Test
     public void testAdd() throws Exception {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
         final TestWindowContainer root = builder.setLayer(0).build();
@@ -69,6 +81,7 @@
         assertEquals(layer2, root.getChildAt(6));
     }
 
+    @Test
     public void testHasChild() throws Exception {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
         final TestWindowContainer root = builder.setLayer(0).build();
@@ -96,9 +109,10 @@
         assertTrue(child2.hasChild(child21));
         assertFalse(child2.hasChild(child11));
         assertFalse(child2.hasChild(child12));
-   }
+    }
 
-    public void testRemove() throws Exception {
+    @Test
+    public void testRemoveImmediately() throws Exception {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
         final TestWindowContainer root = builder.setLayer(0).build();
 
@@ -108,13 +122,16 @@
         final TestWindowContainer child12 = child1.addChildWindow();
         final TestWindowContainer child21 = child2.addChildWindow();
 
-        child12.remove();
+        assertNotNull(child12.getParentWindow());
+        child12.removeImmediately();
         assertNull(child12.getParentWindow());
         assertEquals(1, child1.getChildrenCount());
         assertFalse(child1.hasChild(child12));
         assertFalse(root.hasChild(child12));
 
-        child2.remove();
+        assertTrue(root.hasChild(child2));
+        assertNotNull(child2.getParentWindow());
+        child2.removeImmediately();
         assertNull(child2.getParentWindow());
         assertNull(child21.getParentWindow());
         assertEquals(0, child2.getChildrenCount());
@@ -125,10 +142,11 @@
         assertTrue(root.hasChild(child1));
         assertTrue(root.hasChild(child11));
 
-        root.remove();
+        root.removeImmediately();
         assertEquals(0, root.getChildrenCount());
     }
 
+    @Test
     public void testDetachFromDisplay() throws Exception {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
         final TestWindowContainer root = builder.setLayer(0).build();
@@ -147,6 +165,7 @@
         assertFalse(child21.detachFromDisplay());
     }
 
+    @Test
     public void testIsAnimating() throws Exception {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
         final TestWindowContainer root = builder.setLayer(0).build();
@@ -165,6 +184,7 @@
         assertFalse(child21.isAnimating());
     }
 
+    @Test
     public void testIsVisible() throws Exception {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
         final TestWindowContainer root = builder.setLayer(0).build();
@@ -183,6 +203,33 @@
         assertFalse(child21.isVisible());
     }
 
+    @Test
+    public void testDetachChild() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).build();
+        final TestWindowContainer child1 = root.addChildWindow();
+        final TestWindowContainer child2 = root.addChildWindow();
+        final TestWindowContainer child11 = child1.addChildWindow();
+        final TestWindowContainer child21 = child2.addChildWindow();
+
+        assertTrue(root.hasChild(child2));
+        assertTrue(root.hasChild(child21));
+        root.detachChild(child2);
+        assertFalse(root.hasChild(child2));
+        assertFalse(root.hasChild(child21));
+        assertNull(child2.getParentWindow());
+
+        boolean gotException = false;
+        assertTrue(root.hasChild(child11));
+        try {
+            // Can only detach our direct children.
+            root.detachChild(child11);
+        } catch (IllegalArgumentException e) {
+            gotException = true;
+        }
+        assertTrue(gotException);
+    }
+
     /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
     private class TestWindowContainer extends WindowContainer {
         private final int mLayer;
@@ -190,6 +237,8 @@
         private final boolean mCanDetach;
         private boolean mIsAnimating;
         private boolean mIsVisible;
+        private int mRemoveIfPossibleCount;
+        private int mRemoveImmediatelyCount;
 
         /**
          * Compares 2 window layers and returns -1 if the first is lesser than the second in terms
@@ -252,6 +301,18 @@
         boolean isVisible() {
             return mIsVisible || super.isVisible();
         }
+
+        @Override
+        void removeImmediately() {
+            super.removeImmediately();
+            mRemoveImmediatelyCount++;
+        }
+
+        @Override
+        void removeIfPossible() {
+            super.removeIfPossible();
+            mRemoveIfPossibleCount++;
+        }
     }
 
     private class TestWindowContainerBuilder {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index c55cfb9..4b29a60 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -16,9 +16,14 @@
 
 package com.android.server.wm;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import android.content.Context;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.IWindow;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
@@ -27,6 +32,10 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 /**
  * Tests for the {@link WindowState} class.
@@ -36,25 +45,26 @@
  * Run: adb shell am instrument -w -e class com.android.server.wm.WindowStateTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
  */
 @SmallTest
-public class WindowStateTests extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class WindowStateTests {
 
     private static WindowManagerService sWm = null;
     private WindowToken mWindowToken;
     private final WindowManagerPolicy mPolicy = new TestWindowManagerPolicy();
     private final IWindow mIWindow = new TestIWindow();
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        final Context context = getContext();
-//        final InputManagerService im = new InputManagerService(context);
+        final Context context = InstrumentationRegistry.getTargetContext();
         if (sWm == null) {
             // We only want to do this once for the test process as we don't want WM to try to
             // register a bunch of local services again.
-            sWm = WindowManagerService.main(context, /*im*/ null, true, false, false, mPolicy);
+            sWm = WindowManagerService.main(context, null, true, false, false, mPolicy);
         }
         mWindowToken = new WindowToken(sWm, null, 0, false);
     }
 
+    @Test
     public void testIsParentWindowHidden() throws Exception {
         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
@@ -71,6 +81,7 @@
         assertTrue(child2.isParentWindowHidden());
     }
 
+    @Test
     public void testIsChildWindow() throws Exception {
         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
@@ -83,6 +94,7 @@
         assertFalse(randomWindow.isChildWindow());
     }
 
+    @Test
     public void testHasChild() throws Exception {
         final WindowState win1 = createWindow(null, TYPE_APPLICATION);
         final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW);
@@ -103,6 +115,7 @@
         assertFalse(win2.hasChild(randomWindow));
     }
 
+    @Test
     public void testGetBottomChild() throws Exception {
         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
         assertNull(parentWindow.getBottomChild());
@@ -126,6 +139,7 @@
         assertEquals(child4, parentWindow.getBottomChild());
     }
 
+    @Test
     public void testGetParentWindow() throws Exception {
         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
@@ -136,6 +150,7 @@
         assertEquals(parentWindow, child2.getParentWindow());
     }
 
+    @Test
     public void testGetTopParentWindow() throws Exception {
         final WindowState root = createWindow(null, TYPE_APPLICATION);
         final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index b907161..4505254 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -16,18 +16,24 @@
 
 package com.android.server.wm;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import android.content.Context;
-import android.os.IBinder;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.IWindow;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 /**
  * Tests for the {@link WindowState} class.
@@ -37,15 +43,16 @@
  * Run: adb shell am instrument -w -e class com.android.server.wm.WindowTokenTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
  */
 @SmallTest
-public class WindowTokenTests extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class WindowTokenTests {
 
     private static WindowManagerService sWm = null;
     private final WindowManagerPolicy mPolicy = new TestWindowManagerPolicy();
     private final IWindow mIWindow = new TestIWindow();
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        final Context context = getContext();
+        final Context context = InstrumentationRegistry.getTargetContext();
         if (sWm == null) {
             // We only want to do this once for the test process as we don't want WM to try to
             // register a bunch of local services again.
@@ -53,6 +60,7 @@
         }
     }
 
+    @Test
     public void testAddWindow() throws Exception {
         final TestWindowToken token = new TestWindowToken();
 
@@ -81,6 +89,7 @@
         assertTrue(token.hasWindow(window3));
     }
 
+    @Test
     public void testAdjustAnimLayer() throws Exception {
         final TestWindowToken token = new TestWindowToken();
         final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
@@ -106,6 +115,7 @@
         assertEquals(window3StartLayer + adj, highestLayer);
     }
 
+    @Test
     public void testGetTopWindow() throws Exception {
         final TestWindowToken token = new TestWindowToken();
 
@@ -125,6 +135,7 @@
         assertEquals(window12, token.getTopWindow());
     }
 
+    @Test
     public void testGetWindowIndex() throws Exception {
         final TestWindowToken token = new TestWindowToken();
 
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 2eb37df..c006185 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -733,7 +733,6 @@
      * {@link android.telecom.InCallService.VideoCall}.
      */
     public static abstract class VideoProvider {
-
         /**
          * Video is not being received (no protocol pause was issued).
          * @see #handleCallSessionEvent(int)
@@ -818,6 +817,14 @@
         private static final int MSG_SET_PAUSE_IMAGE = 11;
         private static final int MSG_REMOVE_VIDEO_CALLBACK = 12;
 
+        private static final String SESSION_EVENT_RX_PAUSE_STR = "RX_PAUSE";
+        private static final String SESSION_EVENT_RX_RESUME_STR = "RX_RESUME";
+        private static final String SESSION_EVENT_TX_START_STR = "TX_START";
+        private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP";
+        private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL";
+        private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY";
+        private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN";
+
         private VideoProvider.VideoProviderHandler mMessageHandler;
         private final VideoProvider.VideoProviderBinder mBinder;
 
@@ -1328,6 +1335,32 @@
                 }
             }
         }
+
+        /**
+         * Returns a string representation of a call session event.
+         *
+         * @param event A call session event passed to {@link #handleCallSessionEvent(int)}.
+         * @return String representation of the call session event.
+         * @hide
+         */
+        public static String sessionEventToString(int event) {
+            switch (event) {
+                case SESSION_EVENT_CAMERA_FAILURE:
+                    return SESSION_EVENT_CAMERA_FAILURE_STR;
+                case SESSION_EVENT_CAMERA_READY:
+                    return SESSION_EVENT_CAMERA_READY_STR;
+                case SESSION_EVENT_RX_PAUSE:
+                    return SESSION_EVENT_RX_PAUSE_STR;
+                case SESSION_EVENT_RX_RESUME:
+                    return SESSION_EVENT_RX_RESUME_STR;
+                case SESSION_EVENT_TX_START:
+                    return SESSION_EVENT_TX_START_STR;
+                case SESSION_EVENT_TX_STOP:
+                    return SESSION_EVENT_TX_STOP_STR;
+                default:
+                    return SESSION_EVENT_UNKNOWN_STR + " " + event;
+            }
+        }
     }
 
     private final Listener mConnectionDeathListener = new Listener() {
diff --git a/tests/Assist/res/drawable/assistant.xml b/tests/Assist/res/drawable/assistant.xml
index 2a89dda..56fe2de 100644
--- a/tests/Assist/res/drawable/assistant.xml
+++ b/tests/Assist/res/drawable/assistant.xml
@@ -19,9 +19,6 @@
         android:viewportWidth="48.0"
         android:viewportHeight="48.0">
     <path
-        android:pathData="M0 0h48v48H0z"
-        android:fillColor="#00000000"/>
-    <path
         android:fillColor="#FF000000"
         android:pathData="M38.0,4.0L10.0,4.0C7.79,4.0 6.0,5.79 6.0,8.0l0.0,28.0c0.0,2.21 1.79,4.0 4.0,4.0l8.0,0.0l6.0,6.0 6.0,-6.0l8.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L36.0,8.0c0.0,-2.21 -1.79,-4.0 -4.0,-4.0zM27.75,25.75L24.0,34.0l-3.75,-8.25L12.0,22.0l8.25,-3.75L24.0,10.0l3.75,8.25L36.0,22.0l-8.25,3.75z"/>
 </vector>
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 0d68f62..24cd275 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1407,8 +1407,10 @@
      * @hide
      */
     public boolean isEnterprise() {
-        return allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
-            allowedKeyManagement.get(KeyMgmt.IEEE8021X);
+        return (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
+                || allowedKeyManagement.get(KeyMgmt.IEEE8021X))
+                && enterpriseConfig != null
+                && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
     }
 
     @Override
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 08ad35e..2272306 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -155,6 +155,9 @@
         for (String key : source.mFields.keySet()) {
             mFields.put(key, source.mFields.get(key));
         }
+        mCaCerts = source.mCaCerts;
+        mClientPrivateKey = source.mClientPrivateKey;
+        mClientCertificate = source.mClientCertificate;
         mEapMethod = source.mEapMethod;
         mPhase2Method = source.mPhase2Method;
     }