Merge "send without timestamp is not equivalent to send now" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index 2cf8969..3c81fbb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9630,6 +9630,7 @@
     method public boolean equals(android.content.res.Configuration);
     method public int getLayoutDirection();
     method public boolean isLayoutSizeAtLeast(int);
+    method public boolean isScreenRound();
     method public static boolean needNewResources(int, int);
     method public void readFromParcel(android.os.Parcel);
     method public void setLayoutDirection(java.util.Locale);
@@ -9672,6 +9673,10 @@
     field public static final int SCREENLAYOUT_LONG_NO = 16; // 0x10
     field public static final int SCREENLAYOUT_LONG_UNDEFINED = 0; // 0x0
     field public static final int SCREENLAYOUT_LONG_YES = 32; // 0x20
+    field public static final int SCREENLAYOUT_ROUND_MASK = 768; // 0x300
+    field public static final int SCREENLAYOUT_ROUND_NO = 256; // 0x100
+    field public static final int SCREENLAYOUT_ROUND_UNDEFINED = 0; // 0x0
+    field public static final int SCREENLAYOUT_ROUND_YES = 512; // 0x200
     field public static final int SCREENLAYOUT_SIZE_LARGE = 3; // 0x3
     field public static final int SCREENLAYOUT_SIZE_MASK = 15; // 0xf
     field public static final int SCREENLAYOUT_SIZE_NORMAL = 2; // 0x2
@@ -23094,24 +23099,23 @@
 
   public final class MessageQueue {
     method public void addIdleHandler(android.os.MessageQueue.IdleHandler);
+    method public void addOnFileDescriptorEventListener(java.io.FileDescriptor, int, android.os.MessageQueue.OnFileDescriptorEventListener);
     method public boolean isIdle();
-    method public void registerFileDescriptorCallback(java.io.FileDescriptor, int, android.os.MessageQueue.FileDescriptorCallback);
     method public void removeIdleHandler(android.os.MessageQueue.IdleHandler);
-    method public void unregisterFileDescriptorCallback(java.io.FileDescriptor);
-  }
-
-  public static abstract class MessageQueue.FileDescriptorCallback {
-    ctor public MessageQueue.FileDescriptorCallback();
-    method public int onFileDescriptorEvents(java.io.FileDescriptor, int);
-    field public static final int EVENT_ERROR = 4; // 0x4
-    field public static final int EVENT_INPUT = 1; // 0x1
-    field public static final int EVENT_OUTPUT = 2; // 0x2
+    method public void removeOnFileDescriptorEventListener(java.io.FileDescriptor);
   }
 
   public static abstract interface MessageQueue.IdleHandler {
     method public abstract boolean queueIdle();
   }
 
+  public static abstract interface MessageQueue.OnFileDescriptorEventListener {
+    method public abstract int onFileDescriptorEvents(java.io.FileDescriptor, int);
+    field public static final int EVENT_ERROR = 4; // 0x4
+    field public static final int EVENT_INPUT = 1; // 0x1
+    field public static final int EVENT_OUTPUT = 2; // 0x2
+  }
+
   public final class Messenger implements android.os.Parcelable {
     ctor public Messenger(android.os.Handler);
     ctor public Messenger(android.os.IBinder);
@@ -28887,7 +28891,6 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
     field public static final int START_SOURCE_ASSIST_GESTURE = 4; // 0x4
     field public static final int START_WITH_ASSIST = 1; // 0x1
-    field public static final int START_WITH_SCREENSHOT = 2; // 0x2
   }
 
   public abstract class VoiceInteractionSession implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback {
@@ -28913,7 +28916,6 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle);
-    method public void onHandleScreenshot(android.graphics.Bitmap);
     method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
@@ -34441,6 +34443,8 @@
     method public abstract void setTitle(int);
     method public void setTitleOptionalHint(boolean);
     method public void setType(int);
+    method public void snooze(int);
+    field public static final int SNOOZE_TIME_DEFAULT;
     field public static final int TYPE_FLOATING = 1; // 0x1
     field public static final int TYPE_PRIMARY = 0; // 0x0
   }
@@ -34536,6 +34540,7 @@
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
     field public static final int FLAG_PRESENTATION = 8; // 0x8
     field public static final int FLAG_PRIVATE = 4; // 0x4
+    field public static final int FLAG_ROUND = 16; // 0x10
     field public static final int FLAG_SECURE = 2; // 0x2
     field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
     field public static final int STATE_DOZE = 3; // 0x3
@@ -36504,6 +36509,7 @@
   public class ViewConfiguration {
     ctor public deprecated ViewConfiguration();
     method public static android.view.ViewConfiguration get(android.content.Context);
+    method public static int getDefaultActionModeSnoozeTime();
     method public static int getDoubleTapTimeout();
     method public static deprecated int getEdgeSlop();
     method public static deprecated int getFadingEdgeLength();
diff --git a/api/system-current.txt b/api/system-current.txt
index 263d17a..0dd5fd8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -111,6 +111,7 @@
     field public static final java.lang.String INVOKE_CARRIER_SETUP = "android.permission.INVOKE_CARRIER_SETUP";
     field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
     field public static final java.lang.String KILL_UID = "android.permission.KILL_UID";
+    field public static final java.lang.String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS";
     field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
     field public static final java.lang.String LOOP_RADIO = "android.permission.LOOP_RADIO";
     field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS";
@@ -9940,6 +9941,7 @@
     method public boolean equals(android.content.res.Configuration);
     method public int getLayoutDirection();
     method public boolean isLayoutSizeAtLeast(int);
+    method public boolean isScreenRound();
     method public static boolean needNewResources(int, int);
     method public void readFromParcel(android.os.Parcel);
     method public void setLayoutDirection(java.util.Locale);
@@ -9982,6 +9984,10 @@
     field public static final int SCREENLAYOUT_LONG_NO = 16; // 0x10
     field public static final int SCREENLAYOUT_LONG_UNDEFINED = 0; // 0x0
     field public static final int SCREENLAYOUT_LONG_YES = 32; // 0x20
+    field public static final int SCREENLAYOUT_ROUND_MASK = 768; // 0x300
+    field public static final int SCREENLAYOUT_ROUND_NO = 256; // 0x100
+    field public static final int SCREENLAYOUT_ROUND_UNDEFINED = 0; // 0x0
+    field public static final int SCREENLAYOUT_ROUND_YES = 512; // 0x200
     field public static final int SCREENLAYOUT_SIZE_LARGE = 3; // 0x3
     field public static final int SCREENLAYOUT_SIZE_MASK = 15; // 0xf
     field public static final int SCREENLAYOUT_SIZE_NORMAL = 2; // 0x2
@@ -25008,24 +25014,23 @@
 
   public final class MessageQueue {
     method public void addIdleHandler(android.os.MessageQueue.IdleHandler);
+    method public void addOnFileDescriptorEventListener(java.io.FileDescriptor, int, android.os.MessageQueue.OnFileDescriptorEventListener);
     method public boolean isIdle();
-    method public void registerFileDescriptorCallback(java.io.FileDescriptor, int, android.os.MessageQueue.FileDescriptorCallback);
     method public void removeIdleHandler(android.os.MessageQueue.IdleHandler);
-    method public void unregisterFileDescriptorCallback(java.io.FileDescriptor);
-  }
-
-  public static abstract class MessageQueue.FileDescriptorCallback {
-    ctor public MessageQueue.FileDescriptorCallback();
-    method public int onFileDescriptorEvents(java.io.FileDescriptor, int);
-    field public static final int EVENT_ERROR = 4; // 0x4
-    field public static final int EVENT_INPUT = 1; // 0x1
-    field public static final int EVENT_OUTPUT = 2; // 0x2
+    method public void removeOnFileDescriptorEventListener(java.io.FileDescriptor);
   }
 
   public static abstract interface MessageQueue.IdleHandler {
     method public abstract boolean queueIdle();
   }
 
+  public static abstract interface MessageQueue.OnFileDescriptorEventListener {
+    method public abstract int onFileDescriptorEvents(java.io.FileDescriptor, int);
+    field public static final int EVENT_ERROR = 4; // 0x4
+    field public static final int EVENT_INPUT = 1; // 0x1
+    field public static final int EVENT_OUTPUT = 2; // 0x2
+  }
+
   public final class Messenger implements android.os.Parcelable {
     ctor public Messenger(android.os.Handler);
     ctor public Messenger(android.os.IBinder);
@@ -31016,7 +31021,6 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
     field public static final int START_SOURCE_ASSIST_GESTURE = 4; // 0x4
     field public static final int START_WITH_ASSIST = 1; // 0x1
-    field public static final int START_WITH_SCREENSHOT = 2; // 0x2
   }
 
   public abstract class VoiceInteractionSession implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback {
@@ -31042,7 +31046,6 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle);
-    method public void onHandleScreenshot(android.graphics.Bitmap);
     method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
@@ -36703,6 +36706,8 @@
     method public abstract void setTitle(int);
     method public void setTitleOptionalHint(boolean);
     method public void setType(int);
+    method public void snooze(int);
+    field public static final int SNOOZE_TIME_DEFAULT;
     field public static final int TYPE_FLOATING = 1; // 0x1
     field public static final int TYPE_PRIMARY = 0; // 0x0
   }
@@ -36798,6 +36803,7 @@
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
     field public static final int FLAG_PRESENTATION = 8; // 0x8
     field public static final int FLAG_PRIVATE = 4; // 0x4
+    field public static final int FLAG_ROUND = 16; // 0x10
     field public static final int FLAG_SECURE = 2; // 0x2
     field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
     field public static final int STATE_DOZE = 3; // 0x3
@@ -38766,6 +38772,7 @@
   public class ViewConfiguration {
     ctor public deprecated ViewConfiguration();
     method public static android.view.ViewConfiguration get(android.content.Context);
+    method public static int getDefaultActionModeSnoozeTime();
     method public static int getDoubleTapTimeout();
     method public static deprecated int getEdgeSlop();
     method public static deprecated int getFadingEdgeLength();
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1e9bc54..15cfbcd 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2466,13 +2466,6 @@
             return true;
         }
 
-        case SYSTEM_BACKUP_RESTORED: {
-            data.enforceInterface(IActivityManager.descriptor);
-            systemBackupRestored();
-            reply.writeNoException();
-            return true;
-        }
-
         case NOTIFY_CLEARTEXT_NETWORK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final int uid = data.readInt();
@@ -5759,17 +5752,6 @@
     }
 
     @Override
-    public void systemBackupRestored() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(SYSTEM_BACKUP_RESTORED, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
     public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 05a936c..4ba1055 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -488,7 +488,6 @@
     public void notifyLaunchTaskBehindComplete(IBinder token) throws RemoteException;
     public void notifyEnterAnimationComplete(IBinder token) throws RemoteException;
 
-    public void systemBackupRestored() throws RemoteException;
     public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException;
 
     public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize,
@@ -825,7 +824,6 @@
     int START_IN_PLACE_ANIMATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+240;
     int CHECK_PERMISSION_WITH_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+241;
     int REGISTER_TASK_STACK_LISTENER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+242;
-    int SYSTEM_BACKUP_RESTORED = IBinder.FIRST_CALL_TRANSACTION+243;
 
     // Start of M transactions
     int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+280;
diff --git a/core/java/android/app/backup/RecentsBackupHelper.java b/core/java/android/app/backup/RecentsBackupHelper.java
deleted file mode 100644
index 1a64da6..0000000
--- a/core/java/android/app/backup/RecentsBackupHelper.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.backup;
-
-import android.content.Context;
-import android.os.Environment;
-import android.os.ParcelFileDescriptor;
-import android.util.Slog;
-
-import java.io.File;
-
-/**
- * Helper for saving/restoring 'recent tasks' infrastructure.
- * @hide
- */
-public class RecentsBackupHelper implements BackupHelper {
-    private static final String TAG = "RecentsBackup";
-    private static final boolean DEBUG = false;
-
-    // This must match TaskPersister.TASKS_DIRNAME, but that class is not accessible from here
-    private static final String RECENTS_TASK_DIR = "recent_tasks";
-
-    // Must match TaskPersister.IMAGES_DIRNAME, as above
-    private static final String RECENTS_IMAGE_DIR = "recent_images";
-
-    // At restore time, tasks/thumbnails are placed in these directories alongside
-    // the "live" recents dirs named above.
-    private static final String RECENTS_TASK_RESTORE_DIR = "restored_" + RECENTS_TASK_DIR;
-    private static final String RECENTS_IMAGE_RESTORE_DIR = "restored_" + RECENTS_IMAGE_DIR;
-
-    // Prefixes for tagging the two kinds of recents backup records that we might generate
-    private static final String RECENTS_TASK_KEY = "task:";
-    private static final String RECENTS_IMAGE_KEY = "image:";
-
-    FileBackupHelperBase mTaskFileHelper;
-
-    final File mSystemDir;
-    final File mTasksDir;
-    final File mRestoredTasksDir;
-    final File mRestoredImagesDir;
-    final String[] mRecentFiles;
-    final String[] mRecentKeys;
-
-    /**
-     * @param context The agent context in which this helper instance will run
-     */
-    public RecentsBackupHelper(Context context) {
-        mTaskFileHelper = new FileBackupHelperBase(context);
-
-        mSystemDir = new File(Environment.getDataDirectory(), "system");
-        mTasksDir = new File(mSystemDir, RECENTS_TASK_DIR);
-        mRestoredTasksDir = new File(mSystemDir, RECENTS_TASK_RESTORE_DIR);
-        mRestoredImagesDir = new File(mSystemDir, RECENTS_IMAGE_RESTORE_DIR);
-
-        // Currently we back up only the recent-task descriptions, not the thumbnails
-        File[] recentFiles = mTasksDir.listFiles();
-        if (recentFiles != null) {
-            // We explicitly proceed even if this is a zero-size array
-            final int N = recentFiles.length;
-            mRecentKeys = new String[N];
-            mRecentFiles = new String[N];
-            if (DEBUG) {
-                Slog.i(TAG, "Identifying recents for backup: " + N);
-            }
-            for (int i = 0; i < N; i++) {
-                mRecentKeys[i] = new String(RECENTS_TASK_KEY + recentFiles[i].getName());
-                mRecentFiles[i] = recentFiles[i].getAbsolutePath();
-                if (DEBUG) {
-                    Slog.i(TAG, "   " + mRecentKeys[i]);
-                }
-            }
-        } else {
-            mRecentFiles = mRecentKeys = new String[0];
-        }
-    }
-
-    /**
-     * Task-file key:  RECENTS_TASK_KEY + leaf filename
-     * Thumbnail-file key: RECENTS_IMAGE_KEY + leaf filename
-     */
-    @Override
-    public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
-            ParcelFileDescriptor newState) {
-        FileBackupHelperBase.performBackup_checked(oldState, data, newState,
-                mRecentFiles, mRecentKeys);
-    }
-
-    @Override
-    public void restoreEntity(BackupDataInputStream data) {
-        final String key = data.getKey();
-        File output = null;
-        if (key.startsWith(RECENTS_TASK_KEY)) {
-            String name = key.substring(RECENTS_TASK_KEY.length());
-            output = new File(mRestoredTasksDir, name);
-            mRestoredTasksDir.mkdirs();
-        } else if (key.startsWith(RECENTS_IMAGE_KEY)) {
-            String name = key.substring(RECENTS_IMAGE_KEY.length());
-            output = new File(mRestoredImagesDir, name);
-            mRestoredImagesDir.mkdirs();
-        }
-
-        if (output != null) {
-            if (DEBUG) {
-                Slog.i(TAG, "Restoring key='"
-                        + key + "' to " + output.getAbsolutePath());
-            }
-            mTaskFileHelper.writeFile(output, data);
-        }
-    }
-
-    @Override
-    public void writeNewStateDescription(ParcelFileDescriptor newState) {
-        mTaskFileHelper.writeNewStateDescription(newState);
-    }
-
-}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 8768f40..b22b914 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -96,6 +96,14 @@
     private static final boolean VDBG = false;
 
     /**
+     * Default MAC address reported to a client that does not have the
+     * android.permission.LOCAL_MAC_ADDRESS permission.
+     *
+     * @hide
+     */
+    public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
+
+    /**
      * Sentinel error value for this class. Guaranteed to not equal any other
      * integer constant in this class. Provided as a convenience for functions
      * that require a sentinel error value, for example:
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index bc6d4ce..fd60476 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -156,9 +156,34 @@
      * value indicating that a layout dir has been set to RTL. */
     public static final int SCREENLAYOUT_LAYOUTDIR_RTL = 0x02 << SCREENLAYOUT_LAYOUTDIR_SHIFT;
 
+    /** Constant for {@link #screenLayout}: bits that encode roundness of the screen. */
+    public static final int SCREENLAYOUT_ROUND_MASK = 0x300;
+    /** @hide Constant for {@link #screenLayout}: bit shift to get to screen roundness bits */
+    public static final int SCREENLAYOUT_ROUND_SHIFT = 8;
+    /**
+     * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating
+     * that it is unknown whether or not the screen has a round shape.
+     */
+    public static final int SCREENLAYOUT_ROUND_UNDEFINED = 0x00;
+    /**
+     * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating
+     * that the screen does not have a rounded shape.
+     */
+    public static final int SCREENLAYOUT_ROUND_NO = 0x1 << SCREENLAYOUT_ROUND_SHIFT;
+    /**
+     * Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_ROUND_MASK} value indicating
+     * that the screen has a rounded shape. Corners may not be visible to the user;
+     * developers should pay special attention to the {@link android.view.WindowInsets} delivered
+     * to views for more information about ensuring content is not obscured.
+     *
+     * <p>Corresponds to the <code>-round</code> resource qualifier.</p>
+     */
+    public static final int SCREENLAYOUT_ROUND_YES = 0x2 << SCREENLAYOUT_ROUND_SHIFT;
+
     /** Constant for {@link #screenLayout}: a value indicating that screenLayout is undefined */
     public static final int SCREENLAYOUT_UNDEFINED = SCREENLAYOUT_SIZE_UNDEFINED |
-            SCREENLAYOUT_LONG_UNDEFINED | SCREENLAYOUT_LAYOUTDIR_UNDEFINED;
+            SCREENLAYOUT_LONG_UNDEFINED | SCREENLAYOUT_LAYOUTDIR_UNDEFINED |
+            SCREENLAYOUT_ROUND_UNDEFINED;
 
     /**
      * Special flag we generate to indicate that the screen layout requires
@@ -174,18 +199,22 @@
      * <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size
      * of the screen.  They may be one of
      * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL},
-     * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.
+     * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.</p>
      * 
      * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen
      * is wider/taller than normal.  They may be one of
-     * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.
+     * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.</p>
      * 
      * <p>The {@link #SCREENLAYOUT_LAYOUTDIR_MASK} defines whether the screen layout
      * is either LTR or RTL.  They may be one of
-     * {@link #SCREENLAYOUT_LAYOUTDIR_LTR} or {@link #SCREENLAYOUT_LAYOUTDIR_RTL}.
+     * {@link #SCREENLAYOUT_LAYOUTDIR_LTR} or {@link #SCREENLAYOUT_LAYOUTDIR_RTL}.</p>
+     *
+     * <p>The {@link #SCREENLAYOUT_ROUND_MASK} defines whether the screen has a rounded
+     * shape. They may be one of {@link #SCREENLAYOUT_ROUND_NO} or {@link #SCREENLAYOUT_ROUND_YES}.
+     * </p>
      *
      * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
-     * Multiple Screens</a> for more information.
+     * Multiple Screens</a> for more information.</p>
      */
     public int screenLayout;
 
@@ -1328,6 +1357,16 @@
     }
 
     /**
+     * Return whether the screen has a round shape. Apps may choose to change styling based
+     * on this property, such as the alignment or layout of text or informational icons.
+     *
+     * @return true if the screen is rounded, false otherwise
+     */
+    public boolean isScreenRound() {
+        return (screenLayout & SCREENLAYOUT_ROUND_MASK) == SCREENLAYOUT_ROUND_YES;
+    }
+
+    /**
      *
      * @hide
      */
@@ -1425,6 +1464,17 @@
                 break;
         }
 
+        switch (config.screenLayout & Configuration.SCREENLAYOUT_ROUND_MASK) {
+            case Configuration.SCREENLAYOUT_ROUND_YES:
+                parts.add("round");
+                break;
+            case Configuration.SCREENLAYOUT_ROUND_NO:
+                parts.add("notround");
+                break;
+            default:
+                break;
+        }
+
         switch (config.orientation) {
             case Configuration.ORIENTATION_LANDSCAPE:
                 parts.add("land");
@@ -1640,6 +1690,11 @@
             delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LONG_MASK;
         }
 
+        if ((base.screenLayout & SCREENLAYOUT_ROUND_MASK) !=
+                (change.screenLayout & SCREENLAYOUT_ROUND_MASK)) {
+            delta.screenLayout |= change.screenLayout & SCREENLAYOUT_ROUND_MASK;
+        }
+
         if ((base.uiMode & UI_MODE_TYPE_MASK) != (change.uiMode & UI_MODE_TYPE_MASK)) {
             delta.uiMode |= change.uiMode & UI_MODE_TYPE_MASK;
         }
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index d08c52b..9046e81 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -371,7 +371,6 @@
             mDeviceImpl.stopRepeating();
         } catch (IllegalStateException e) {
             // OK: Camera device may already be closed, nothing else to do
-            Log.w(TAG, mIdString + "The camera device was already closed: ", e);
 
             // TODO: Fire onClosed anytime we get the device onClosed or the ISE?
             // or just suppress the ISE only and rely onClosed.
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 77200a5..c1b4a1f 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -106,13 +106,13 @@
 
     ProxyInfo getDefaultProxy();
 
-    boolean prepareVpn(String oldPackage, String newPackage);
+    boolean prepareVpn(String oldPackage, String newPackage, int userId);
 
-    void setVpnPackageAuthorization(boolean authorized);
+    void setVpnPackageAuthorization(String packageName, int userId, boolean authorized);
 
     ParcelFileDescriptor establishVpn(in VpnConfig config);
 
-    VpnConfig getVpnConfig();
+    VpnConfig getVpnConfig(int userId);
 
     void startLegacyVpn(in VpnProfile profile);
 
diff --git a/core/java/android/net/IpReachabilityMonitor.java b/core/java/android/net/IpReachabilityMonitor.java
index 7e1c05b..add8774 100644
--- a/core/java/android/net/IpReachabilityMonitor.java
+++ b/core/java/android/net/IpReachabilityMonitor.java
@@ -75,7 +75,6 @@
     private boolean mRunning;
     final private Thread mObserverThread;
 
-    // TODO: consider passing in a NetworkInterface object from the caller.
     public IpReachabilityMonitor(String ifName, Callback callback) throws IllegalArgumentException {
         mInterfaceName = ifName;
         int ifIndex = -1;
@@ -154,6 +153,12 @@
         }
     }
 
+    private boolean stillRunning() {
+        synchronized (mLock) {
+            return mRunning;
+        }
+    }
+
     public void updateLinkProperties(LinkProperties lp) {
         if (!mInterfaceName.equals(lp.getInterfaceName())) {
             // TODO: figure out how to cope with interface changes.
@@ -204,6 +209,47 @@
         }
     }
 
+    public void probeAll() {
+        Set<InetAddress> ipProbeList = new HashSet<InetAddress>();
+        synchronized (mLock) {
+            ipProbeList.addAll(mIpWatchList);
+        }
+        for (InetAddress target : ipProbeList) {
+            if (!stillRunning()) { break; }
+            probeIp(target);
+        }
+    }
+
+    private void probeIp(InetAddress ip) {
+        // This currently does not cause neighbor probing if the target |ip|
+        // has been confirmed reachable within the past "delay_probe_time"
+        // seconds, i.e. within the past 5 seconds.
+        //
+        // TODO: replace with a transition directly to NUD_PROBE state once
+        // kernels are updated to do so correctly.
+        if (DBG) { Log.d(TAG, "Probing ip=" + ip.getHostAddress()); }
+
+        final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
+                1, ip, StructNdMsg.NUD_DELAY, mInterfaceIndex, null);
+        NetlinkSocket nlSocket = null;
+
+        try {
+            nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
+            nlSocket.connectToKernel();
+            nlSocket.sendMessage(msg, 0, msg.length, 300);
+            final NetlinkMessage response = NetlinkMessage.parse(nlSocket.recvMessage(300));
+            if (response != null && response instanceof NetlinkErrorMessage) {
+                Log.e(TAG, "Error probing ip=" + response.toString());
+            }
+        } catch (ErrnoException | InterruptedIOException | SocketException e) {
+            Log.d(TAG, "Error probing ip=" + ip.getHostAddress(), e);
+        }
+
+        if (nlSocket != null) {
+            nlSocket.close();
+        }
+    }
+
 
     private final class NetlinkSocketObserver implements Runnable {
         private static final String TAG = "NetlinkSocketObserver";
@@ -242,12 +288,6 @@
             if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
         }
 
-        private boolean stillRunning() {
-            synchronized (mLock) {
-                return mRunning;
-            }
-        }
-
         private void clearNetlinkSocket() {
             if (mSocket != null) {
                 mSocket.close();
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index ab70485..cf747cf 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -619,6 +619,7 @@
                 case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break;
                 case NET_CAPABILITY_TRUSTED:        capabilities += "TRUSTED"; break;
                 case NET_CAPABILITY_NOT_VPN:        capabilities += "NOT_VPN"; break;
+                case NET_CAPABILITY_VALIDATED:      capabilities += "VALIDATED"; break;
             }
             if (++i < types.length) capabilities += "&";
         }
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index a0e65eb..2bb48b3 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -156,7 +156,7 @@
      */
     public static Intent prepare(Context context) {
         try {
-            if (getService().prepareVpn(context.getPackageName(), null)) {
+            if (getService().prepareVpn(context.getPackageName(), null, UserHandle.myUserId())) {
                 return null;
             }
         } catch (RemoteException e) {
@@ -182,10 +182,11 @@
         String packageName = context.getPackageName();
         try {
             // Only prepare if we're not already prepared.
-            if (!cm.prepareVpn(packageName, null)) {
-                cm.prepareVpn(null, packageName);
+            int userId = UserHandle.myUserId();
+            if (!cm.prepareVpn(packageName, null, userId)) {
+                cm.prepareVpn(null, packageName, userId);
             }
-            cm.setVpnPackageAuthorization(true);
+            cm.setVpnPackageAuthorization(packageName, userId, true);
         } catch (RemoteException e) {
             // ignore
         }
diff --git a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java b/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
index d4b572c..b5f5817 100644
--- a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
+++ b/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
@@ -21,9 +21,11 @@
 import android.net.netlink.StructNlAttr;
 import android.net.netlink.StructNlMsgHdr;
 import android.net.netlink.NetlinkMessage;
+import android.system.OsConstants;
 import android.util.Log;
 
 import java.net.InetAddress;
+import java.net.Inet6Address;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
@@ -131,6 +133,34 @@
         return bytes;
     }
 
+    /**
+     * A convenience method to create an RTM_NEWNEIGH message, to modify
+     * the kernel's state information for a specific neighbor.
+     */
+    public static byte[] newNewNeighborMessage(
+            int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) {
+        final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
+        nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH;
+        nlmsghdr.nlmsg_flags = StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_REPLACE;
+        nlmsghdr.nlmsg_seq = seqNo;
+
+        final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr);
+        msg.mNdmsg = new StructNdMsg();
+        msg.mNdmsg.ndm_family =
+                (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
+        msg.mNdmsg.ndm_ifindex = ifIndex;
+        msg.mNdmsg.ndm_state = nudState;
+        msg.mDestination = ip;
+        msg.mLinkLayerAddr = llAddr;  // might be null
+
+        final byte[] bytes = new byte[msg.getRequiredSpace()];
+        nlmsghdr.nlmsg_len = bytes.length;
+        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+        byteBuffer.order(ByteOrder.nativeOrder());
+        msg.pack(byteBuffer);
+        return bytes;
+    }
+
     private StructNdMsg mNdmsg;
     private InetAddress mDestination;
     private byte[] mLinkLayerAddr;
@@ -166,6 +196,41 @@
         return mCacheInfo;
     }
 
+    public int getRequiredSpace() {
+        int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
+        if (mDestination != null) {
+            spaceRequired += NetlinkConstants.alignedLengthOf(
+                    StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length);
+        }
+        if (mLinkLayerAddr != null) {
+            spaceRequired += NetlinkConstants.alignedLengthOf(
+                    StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length);
+        }
+        // Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO
+        // attributes appended.  Fix later, if necessary.
+        return spaceRequired;
+    }
+
+    private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) {
+        final StructNlAttr nlAttr = new StructNlAttr();
+        nlAttr.nla_type = nlType;
+        nlAttr.nla_value = nlValue;
+        nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length);
+        nlAttr.pack(byteBuffer);
+    }
+
+    public void pack(ByteBuffer byteBuffer) {
+        getHeader().pack(byteBuffer) ;
+        mNdmsg.pack(byteBuffer);
+
+        if (mDestination != null) {
+            packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer);
+        }
+        if (mLinkLayerAddr != null) {
+            packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer);
+        }
+    }
+
     @Override
     public String toString() {
         final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
diff --git a/core/java/android/net/netlink/StructNdMsg.java b/core/java/android/net/netlink/StructNdMsg.java
index e66d45d..ca1cbbb 100644
--- a/core/java/android/net/netlink/StructNdMsg.java
+++ b/core/java/android/net/netlink/StructNdMsg.java
@@ -123,9 +123,7 @@
         ndm_family = (byte) OsConstants.AF_UNSPEC;
     }
 
-    public boolean pack(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return false; }
-
+    public void pack(ByteBuffer byteBuffer) {
         // The ByteOrder must have already been set by the caller.  In most
         // cases ByteOrder.nativeOrder() is correct, with the exception
         // of usage within unittests.
@@ -136,7 +134,6 @@
         byteBuffer.putShort(ndm_state);
         byteBuffer.put(ndm_flags);
         byteBuffer.put(ndm_type);
-        return true;
     }
 
     public boolean nudConnected() {
diff --git a/core/java/android/net/netlink/StructNlAttr.java b/core/java/android/net/netlink/StructNlAttr.java
index 9aef4c7..597a6aa 100644
--- a/core/java/android/net/netlink/StructNlAttr.java
+++ b/core/java/android/net/netlink/StructNlAttr.java
@@ -116,6 +116,14 @@
         }
     }
 
+    public void pack(ByteBuffer byteBuffer) {
+        final int originalPosition = byteBuffer.position();
+        byteBuffer.putShort(nla_len);
+        byteBuffer.putShort(nla_type);
+        byteBuffer.put(nla_value);
+        byteBuffer.position(originalPosition + getAlignedLength());
+    }
+
     @Override
     public String toString() {
         return "StructNlAttr{ "
diff --git a/core/java/android/net/netlink/StructNlMsgErr.java b/core/java/android/net/netlink/StructNlMsgErr.java
index 5da19a2..6b02650 100644
--- a/core/java/android/net/netlink/StructNlMsgErr.java
+++ b/core/java/android/net/netlink/StructNlMsgErr.java
@@ -57,9 +57,7 @@
         msg = null;
     }
 
-    public boolean pack(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return false; }
-
+    public void pack(ByteBuffer byteBuffer) {
         // The ByteOrder must have already been set by the caller.  In most
         // cases ByteOrder.nativeOrder() is correct, with the possible
         // exception of usage within unittests.
@@ -67,7 +65,6 @@
         if (msg != null) {
             msg.pack(byteBuffer);
         }
-        return true;
     }
 
     @Override
diff --git a/core/java/android/net/netlink/StructNlMsgHdr.java b/core/java/android/net/netlink/StructNlMsgHdr.java
index 67925ac..98ab5e7 100644
--- a/core/java/android/net/netlink/StructNlMsgHdr.java
+++ b/core/java/android/net/netlink/StructNlMsgHdr.java
@@ -39,6 +39,12 @@
     public static final short NLM_F_ROOT    = 0x0100;
     public static final short NLM_F_MATCH   = 0x0200;
     public static final short NLM_F_DUMP    = NLM_F_ROOT|NLM_F_MATCH;
+    // Flags for a NEW request.
+    public static final short NLM_F_REPLACE   = 0x100;
+    public static final short NLM_F_EXCL      = 0x200;
+    public static final short NLM_F_CREATE    = 0x400;
+    public static final short NLM_F_APPEND    = 0x800;
+
 
     public static String stringForNlMsgFlags(short flags) {
         final StringBuilder sb = new StringBuilder();
@@ -106,9 +112,7 @@
         nlmsg_pid = 0;
     }
 
-    public boolean pack(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return false; }
-
+    public void pack(ByteBuffer byteBuffer) {
         // The ByteOrder must have already been set by the caller.  In most
         // cases ByteOrder.nativeOrder() is correct, with the possible
         // exception of usage within unittests.
@@ -117,7 +121,6 @@
         byteBuffer.putShort(nlmsg_flags);
         byteBuffer.putInt(nlmsg_seq);
         byteBuffer.putInt(nlmsg_pid);
-        return true;
     }
 
     @Override
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 7dd4f94..4f2e968 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -160,67 +160,67 @@
     }
 
     /**
-     * Registers a file descriptor callback to receive notification when file descriptor
+     * Adds a file descriptor listener to receive notification when file descriptor
      * related events occur.
      * <p>
      * If the file descriptor has already been registered, the specified events
-     * and callback will replace any that were previously associated with it.
-     * It is not possible to set more than one callback per file descriptor.
+     * and listener will replace any that were previously associated with it.
+     * It is not possible to set more than one listener per file descriptor.
      * </p><p>
-     * It is important to always unregister the callback when the file descriptor
+     * It is important to always unregister the listener when the file descriptor
      * is no longer of use.
      * </p>
      *
-     * @param fd The file descriptor for which a callback will be registered.
+     * @param fd The file descriptor for which a listener will be registered.
      * @param events The set of events to receive: a combination of the
-     * {@link FileDescriptorCallback#EVENT_INPUT},
-     * {@link FileDescriptorCallback#EVENT_OUTPUT}, and
-     * {@link FileDescriptorCallback#EVENT_ERROR} event masks.  If the requested
-     * set of events is zero, then the callback is unregistered.
-     * @param callback The callback to invoke when file descriptor events occur.
+     * {@link OnFileDescriptorEventListener#EVENT_INPUT},
+     * {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and
+     * {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks.  If the requested
+     * set of events is zero, then the listener is unregistered.
+     * @param listener The listener to invoke when file descriptor events occur.
      *
-     * @see FileDescriptorCallback
-     * @see #unregisterFileDescriptorCallback
+     * @see OnFileDescriptorEventListener
+     * @see #removeOnFileDescriptorEventListener
      */
-    public void registerFileDescriptorCallback(@NonNull FileDescriptor fd,
-            @FileDescriptorCallback.Events int events,
-            @NonNull FileDescriptorCallback callback) {
+    public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
+            @OnFileDescriptorEventListener.Events int events,
+            @NonNull OnFileDescriptorEventListener listener) {
         if (fd == null) {
             throw new IllegalArgumentException("fd must not be null");
         }
-        if (callback == null) {
-            throw new IllegalArgumentException("callback must not be null");
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
         }
 
         synchronized (this) {
-            setFileDescriptorCallbackLocked(fd, events, callback);
+            updateOnFileDescriptorEventListenerLocked(fd, events, listener);
         }
     }
 
     /**
-     * Unregisters a file descriptor callback.
+     * Removes a file descriptor listener.
      * <p>
-     * This method does nothing if no callback has been registered for the
+     * This method does nothing if no listener has been registered for the
      * specified file descriptor.
      * </p>
      *
-     * @param fd The file descriptor whose callback will be unregistered.
+     * @param fd The file descriptor whose listener will be unregistered.
      *
-     * @see FileDescriptorCallback
-     * @see #registerFileDescriptorCallback
+     * @see OnFileDescriptorEventListener
+     * @see #addOnFileDescriptorEventListener
      */
-    public void unregisterFileDescriptorCallback(@NonNull FileDescriptor fd) {
+    public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
         if (fd == null) {
             throw new IllegalArgumentException("fd must not be null");
         }
 
         synchronized (this) {
-            setFileDescriptorCallbackLocked(fd, 0, null);
+            updateOnFileDescriptorEventListenerLocked(fd, 0, null);
         }
     }
 
-    private void setFileDescriptorCallbackLocked(FileDescriptor fd, int events,
-            FileDescriptorCallback callback) {
+    private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
+            OnFileDescriptorEventListener listener) {
         final int fdNum = fd.getInt$();
 
         int index = -1;
@@ -236,15 +236,15 @@
         }
 
         if (events != 0) {
-            events |= FileDescriptorCallback.EVENT_ERROR;
+            events |= OnFileDescriptorEventListener.EVENT_ERROR;
             if (record == null) {
                 if (mFileDescriptorRecords == null) {
                     mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
                 }
-                record = new FileDescriptorRecord(fd, events, callback);
+                record = new FileDescriptorRecord(fd, events, listener);
                 mFileDescriptorRecords.put(fdNum, record);
             } else {
-                record.mCallback = callback;
+                record.mListener = listener;
                 record.mEvents = events;
                 record.mSeq += 1;
             }
@@ -260,12 +260,12 @@
         // Get the file descriptor record and any state that might change.
         final FileDescriptorRecord record;
         final int oldWatchedEvents;
-        final FileDescriptorCallback callback;
+        final OnFileDescriptorEventListener listener;
         final int seq;
         synchronized (this) {
             record = mFileDescriptorRecords.get(fd);
             if (record == null) {
-                return 0; // spurious, no callback registered
+                return 0; // spurious, no listener registered
             }
 
             oldWatchedEvents = record.mEvents;
@@ -274,19 +274,19 @@
                 return oldWatchedEvents; // spurious, watched events changed
             }
 
-            callback = record.mCallback;
+            listener = record.mListener;
             seq = record.mSeq;
         }
 
-        // Invoke the callback outside of the lock.
-        int newWatchedEvents = callback.onFileDescriptorEvents(
+        // Invoke the listener outside of the lock.
+        int newWatchedEvents = listener.onFileDescriptorEvents(
                 record.mDescriptor, events);
         if (newWatchedEvents != 0) {
-            newWatchedEvents |= FileDescriptorCallback.EVENT_ERROR;
+            newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
         }
 
-        // Update the file descriptor record if the callback changed the set of
-        // events to watch and the callback itself hasn't been updated since.
+        // Update the file descriptor record if the listener changed the set of
+        // events to watch and the listener itself hasn't been updated since.
         if (newWatchedEvents != oldWatchedEvents) {
             synchronized (this) {
                 int index = mFileDescriptorRecords.indexOfKey(fd);
@@ -786,23 +786,23 @@
     }
 
     /**
-     * A callback which is invoked when file descriptor related events occur.
+     * A listener which is invoked when file descriptor related events occur.
      */
-    public static abstract class FileDescriptorCallback {
+    public interface OnFileDescriptorEventListener {
         /**
          * File descriptor event: Indicates that the file descriptor is ready for input
          * operations, such as reading.
          * <p>
-         * The callback should read all available data from the file descriptor
-         * then return <code>true</code> to keep the callback active or <code>false</code>
-         * to remove the callback.
+         * The listener should read all available data from the file descriptor
+         * then return <code>true</code> to keep the listener active or <code>false</code>
+         * to remove the listener.
          * </p><p>
          * In the case of a socket, this event may be generated to indicate
-         * that there is at least one incoming connection that the callback
+         * that there is at least one incoming connection that the listener
          * should accept.
          * </p><p>
          * This event will only be generated if the {@link #EVENT_INPUT} event mask was
-         * specified when the callback was added.
+         * specified when the listener was added.
          * </p>
          */
         public static final int EVENT_INPUT = 1 << 0;
@@ -811,14 +811,14 @@
          * File descriptor event: Indicates that the file descriptor is ready for output
          * operations, such as writing.
          * <p>
-         * The callback should write as much data as it needs.  If it could not
+         * The listener should write as much data as it needs.  If it could not
          * write everything at once, then it should return <code>true</code> to
-         * keep the callback active.  Otherwise, it should return <code>false</code>
-         * to remove the callback then re-register it later when it needs to write
+         * keep the listener active.  Otherwise, it should return <code>false</code>
+         * to remove the listener then re-register it later when it needs to write
          * something else.
          * </p><p>
          * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
-         * specified when the callback was added.
+         * specified when the listener was added.
          * </p>
          */
         public static final int EVENT_OUTPUT = 1 << 1;
@@ -831,7 +831,7 @@
          * is when the remote peer of a socket or pipe closes its end of the connection.
          * </p><p>
          * This event may be generated at any time regardless of whether the
-         * {@link #EVENT_ERROR} event mask was specified when the callback was added.
+         * {@link #EVENT_ERROR} event mask was specified when the listener was added.
          * </p>
          */
         public static final int EVENT_ERROR = 1 << 2;
@@ -843,35 +843,30 @@
 
         /**
          * Called when a file descriptor receives events.
-         * <p>
-         * The default implementation does nothing and returns 0 to unregister the callback.
-         * </p>
          *
          * @param fd The file descriptor.
          * @param events The set of events that occurred: a combination of the
          * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
-         * @return The new set of events to watch, or 0 to unregister the callback.
+         * @return The new set of events to watch, or 0 to unregister the listener.
          *
          * @see #EVENT_INPUT
          * @see #EVENT_OUTPUT
          * @see #EVENT_ERROR
          */
-        public @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events) {
-            return 0;
-        }
+        @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events);
     }
 
     private static final class FileDescriptorRecord {
         public final FileDescriptor mDescriptor;
         public int mEvents;
-        public FileDescriptorCallback mCallback;
+        public OnFileDescriptorEventListener mListener;
         public int mSeq;
 
         public FileDescriptorRecord(FileDescriptor descriptor,
-                int events, FileDescriptorCallback callback) {
+                int events, OnFileDescriptorEventListener listener) {
             mDescriptor = descriptor;
             mEvents = events;
-            mCallback = callback;
+            mListener = listener;
         }
     }
 }
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 5b26304..c24f3fe 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -25,7 +25,7 @@
 
 import android.content.BroadcastReceiver;
 import android.content.ContentProvider;
-import android.os.MessageQueue.FileDescriptorCallback;
+import android.os.MessageQueue.OnFileDescriptorEventListener;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
@@ -236,19 +236,19 @@
         final FileDescriptor[] comm = createCommSocketPair();
         final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
         final MessageQueue queue = handler.getLooper().getQueue();
-        queue.registerFileDescriptorCallback(comm[1],
-                FileDescriptorCallback.EVENT_INPUT, new FileDescriptorCallback() {
+        queue.addOnFileDescriptorEventListener(comm[1],
+                OnFileDescriptorEventListener.EVENT_INPUT, new OnFileDescriptorEventListener() {
             @Override
             public int onFileDescriptorEvents(FileDescriptor fd, int events) {
                 Status status = null;
-                if ((events & FileDescriptorCallback.EVENT_INPUT) != 0) {
+                if ((events & OnFileDescriptorEventListener.EVENT_INPUT) != 0) {
                     final byte[] buf = new byte[MAX_STATUS];
                     status = readCommStatus(fd, buf);
-                } else if ((events & FileDescriptorCallback.EVENT_ERROR) != 0) {
+                } else if ((events & OnFileDescriptorEventListener.EVENT_ERROR) != 0) {
                     status = new Status(Status.DEAD);
                 }
                 if (status != null) {
-                    queue.unregisterFileDescriptorCallback(fd);
+                    queue.removeOnFileDescriptorEventListener(fd);
                     IoUtils.closeQuietly(fd);
                     listener.onClose(status.asIOException());
                     return 0;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ef0dc3e..37645b5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5417,6 +5417,14 @@
         public static final String EMERGENCY_ASSISTANCE_APPLICATION = "emergency_assistance_application";
 
         /**
+         * Specifies whether the current app context on scren (assist data) will be sent to the
+         * assist application (active voice interaction service).
+         *
+         * @hide
+         */
+        public static final String ASSIST_STRUCTURE_ENABLED = "assist_structure_enabled";
+
+        /**
          * Names of the packages that the current user has explicitly allowed to
          * see all of the user's notifications, separated by ':'.
          *
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 7956a3f..b8493d4 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -27,6 +27,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -322,7 +326,7 @@
         if (!isBound()) return;
         try {
             getNotificationInterface().cancelNotificationsFromListener(mWrapper,
-                    new String[] {key});
+                    new String[] { key });
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
         }
@@ -464,6 +468,8 @@
             for (int i = 0; i < N; i++) {
                 Notification notification = list.get(i).getNotification();
                 Builder.rebuild(getContext(), notification);
+                // convert icon metadata to legacy format for older clients
+                createLegacyIconExtras(notification);
             }
             return list.toArray(new StatusBarNotification[N]);
         } catch (android.os.RemoteException ex) {
@@ -636,6 +642,24 @@
         }
     }
 
+    /** Convert new-style Icons to legacy representations for pre-M clients. */
+    private void createLegacyIconExtras(Notification n) {
+        Icon smallIcon = n.getSmallIcon();
+        Icon largeIcon = n.getLargeIcon();
+        if (smallIcon.getType() == Icon.TYPE_RESOURCE) {
+            n.extras.putInt(Notification.EXTRA_SMALL_ICON, smallIcon.getResId());
+            n.icon = smallIcon.getResId();
+        }
+        if (largeIcon != null) {
+            Drawable d = largeIcon.loadDrawable(getContext());
+            if (d != null && d instanceof BitmapDrawable) {
+                final Bitmap largeIconBits = ((BitmapDrawable) d).getBitmap();
+                n.extras.putParcelable(Notification.EXTRA_LARGE_ICON, largeIconBits);
+                n.largeIcon = largeIconBits;
+            }
+        }
+    }
+
     private class INotificationListenerWrapper extends INotificationListener.Stub {
         @Override
         public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
@@ -649,6 +673,9 @@
             }
             Notification.Builder.rebuild(getContext(), sbn.getNotification());
 
+            // convert icon metadata to legacy format for older clients
+            createLegacyIconExtras(sbn.getNotification());
+
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
             synchronized (mWrapper) {
                 applyUpdate(update);
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 8c89ddb..77e2125 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -77,6 +77,7 @@
     public static final int START_WITH_ASSIST = 1<<0;
 
     /**
+     * @hide
      * Flag for use with {@link #showSession}: request that the session be started with
      * a screen shot of the currently focused activity.
      */
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 71b7f76..f122d10 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -820,6 +820,7 @@
     public void onHandleAssist(Bundle assistBundle) {
     }
 
+    /** @hide */
     public void onHandleScreenshot(Bitmap screenshot) {
     }
 
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 016541f..b93a4a5 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -168,8 +168,6 @@
         final Rect mFinalStableInsets = new Rect();
         final Configuration mConfiguration = new Configuration();
 
-        private boolean mWindowIsRound;
-
         final WindowManager.LayoutParams mLayout
                 = new WindowManager.LayoutParams();
         IWindowSession mSession;
@@ -640,7 +638,6 @@
                         // Retrieve watch round info
                         TypedArray windowStyle = obtainStyledAttributes(
                                 com.android.internal.R.styleable.Window);
-                        mWindowIsRound = ScreenShapeHelper.getWindowIsRound(getResources());
                         windowStyle.recycle();
 
                         // Add window
@@ -776,7 +773,8 @@
                             mFinalStableInsets.set(mDispatchedStableInsets);
                             mFinalSystemInsets.bottom = mIWallpaperEngine.mDisplayPadding.bottom;
                             WindowInsets insets = new WindowInsets(mFinalSystemInsets,
-                                    null, mFinalStableInsets, mWindowIsRound);
+                                    null, mFinalStableInsets,
+                                    getResources().getConfiguration().isScreenRound());
                             onApplyWindowInsets(insets);
                         }
 
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index 9f202a9..9f00455 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -44,6 +44,12 @@
      */
     public static final int TYPE_FLOATING = 1;
 
+    /**
+     * Default snooze time.
+     */
+    public static final int SNOOZE_TIME_DEFAULT =
+            ViewConfiguration.getDefaultActionModeSnoozeTime();
+
     private Object mTag;
     private boolean mTitleOptionalHint;
     private int mType = TYPE_PRIMARY;
@@ -207,6 +213,19 @@
     public void invalidateContentRect() {}
 
     /**
+     * Hide the action mode view from obstructing the content below for a short period.
+     * This only makes sense for action modes that support dynamic positioning on the screen.
+     * If this method is called again before the snooze time expires, the later snooze will
+     * cancel the former and then take effect.
+     * NOTE that there is an internal limit to how long the mode can be snoozed for. It's typically
+     * about a few seconds.
+     *
+     * @param snoozeTime The number of milliseconds to snooze for.
+     * @see #SNOOZE_TIME_DEFAULT
+     */
+    public void snooze(int snoozeTime) {}
+
+    /**
      * Finish and close this action mode. The action mode's {@link ActionMode.Callback} will
      * have its {@link Callback#onDestroyActionMode(ActionMode)} method called.
      */
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index d4b971a..5a587fe 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -172,6 +172,17 @@
     public static final int FLAG_PRESENTATION = 1 << 3;
 
     /**
+     * Display flag: Indicates that the display has a round shape.
+     * <p>
+     * This flag identifies displays that are circular, elliptical or otherwise
+     * do not permit the user to see all the way to the logical corners of the display.
+     * </p>
+     *
+     * @see #getFlags
+     */
+    public static final int FLAG_ROUND = 1 << 4;
+
+    /**
      * Display flag: Indicates that the contents of the display should not be scaled
      * to fit the physical screen dimensions.  Used for development only to emulate
      * devices with smaller physicals screens while preserving density.
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index b9fde8a..cf17990 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -609,6 +609,9 @@
         if ((flags & Display.FLAG_SCALING_DISABLED) != 0) {
             result.append(", FLAG_SCALING_DISABLED");
         }
+        if ((flags & Display.FLAG_ROUND) != 0) {
+            result.append(", FLAG_ROUND");
+        }
         return result.toString();
     }
 }
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 4e91ad4..8c6fa3f 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -213,6 +213,11 @@
     private static final int OVERFLING_DISTANCE = 6;
 
     /**
+     * Default time to snooze an action mode for.
+     */
+    private static final int ACTION_MODE_SNOOZE_TIME_DEFAULT = 2000;
+
+    /**
      * Configuration values for overriding {@link #hasPermanentMenuKey()} behavior.
      * These constants must match the definition in res/values/config.xml.
      */
@@ -732,6 +737,13 @@
     }
 
     /**
+     * @return the default duration in milliseconds for {@link ActionMode#snooze(int)}.
+     */
+    public static int getDefaultActionModeSnoozeTime() {
+        return ACTION_MODE_SNOOZE_TIME_DEFAULT;
+    }
+
+    /**
      * Report if the device has a permanent menu key available to the user.
      *
      * <p>As of Android 3.0, devices may not have a permanent menu key available.
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index f18b7ac..bd45007 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -80,18 +80,12 @@
 
     /**
      * The interpolator of the underlying Animator object. By default, we don't set the interpolator
-     * on the Animator and just use its default interpolator. If the interpolator is ever set on
-     * this Animator, then we use the interpolator that it was set to.
+     * on the Animator and just use its default interpolator. If the interpolator is set to a
+     * non-null value on this Animator, then we use the interpolator that it was set to.
      */
     private TimeInterpolator mInterpolator;
 
     /**
-     * A flag indicating whether the interpolator has been set on this object. If not, we don't set
-     * the interpolator on the underlying Animator, but instead just use its default interpolator.
-     */
-    private boolean mInterpolatorSet = false;
-
-    /**
      * Listener for the lifecycle events of the underlying ValueAnimator object.
      */
     private Animator.AnimatorListener mListener = null;
@@ -338,7 +332,6 @@
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
-        mInterpolatorSet = true;
         mInterpolator = interpolator;
         return this;
     }
@@ -349,7 +342,7 @@
      * @return The timing interpolator for this animation.
      */
     public TimeInterpolator getInterpolator() {
-        if (mInterpolatorSet) {
+        if (mInterpolator != null) {
             return mInterpolator;
         } else {
             // Just return the default from ValueAnimator, since that's what we'd get if
@@ -897,7 +890,7 @@
         if (mDurationSet) {
             animator.setDuration(mDuration);
         }
-        if (mInterpolatorSet) {
+        if (mInterpolator != null) {
             animator.setInterpolator(mInterpolator);
         }
         animator.start();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b7d902c..23f3b62 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -122,7 +122,6 @@
     private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
 
     // properties used by emulator to determine display shape
-    public static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
     public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
             "ro.emu.win_outset_bottom_px";
 
@@ -341,8 +340,6 @@
     /** Set to true once doDie() has been called. */
     private boolean mRemoved;
 
-    private final boolean mWindowIsRound;
-
     /**
      * Consistency verifier for debugging purposes.
      */
@@ -397,7 +394,6 @@
         mChoreographer = Choreographer.getInstance();
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
         loadSystemProperties();
-        mWindowIsRound = ScreenShapeHelper.getWindowIsRound(context.getResources());
     }
 
     public static void addFirstDrawHandler(Runnable callback) {
@@ -1271,7 +1267,8 @@
                 stableInsets = mPendingStableInsets;
             }
             mLastWindowInsets = new WindowInsets(contentInsets,
-                    null /* windowDecorInsets */, stableInsets, mWindowIsRound);
+                    null /* windowDecorInsets */, stableInsets,
+                    mContext.getResources().getConfiguration().isScreenRound());
         }
         return mLastWindowInsets;
     }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index c829783..d558c7b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -233,6 +233,24 @@
 
     final CursorAnchorInfoNotifier mCursorAnchorInfoNotifier = new CursorAnchorInfoNotifier();
 
+    private final Runnable mHideFloatingToolbar = new Runnable() {
+        @Override
+        public void run() {
+            if (mSelectionActionMode != null) {
+                mSelectionActionMode.snooze(ActionMode.SNOOZE_TIME_DEFAULT);
+            }
+        }
+    };
+
+    private final Runnable mShowFloatingToolbar = new Runnable() {
+        @Override
+        public void run() {
+            if (mSelectionActionMode != null) {
+                mSelectionActionMode.snooze(0);  // snooze off.
+            }
+        }
+    };
+
     Editor(TextView textView) {
         mTextView = textView;
         // Synchronize the filter list, which places the undo input filter at the end.
@@ -358,6 +376,9 @@
             mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
         }
 
+        mTextView.removeCallbacks(mHideFloatingToolbar);
+        mTextView.removeCallbacks(mShowFloatingToolbar);
+
         destroyDisplayListsData();
 
         if (mSpellChecker != null) {
@@ -1169,6 +1190,8 @@
     }
 
     void onTouchEvent(MotionEvent event) {
+        updateFloatingToolbarVisibility(event);
+
         if (hasSelectionController()) {
             getSelectionController().onTouchEvent(event);
         }
@@ -1189,6 +1212,37 @@
         }
     }
 
+    private void updateFloatingToolbarVisibility(MotionEvent event) {
+        if (mSelectionActionMode != null) {
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_MOVE:
+                    hideFloatingToolbar();
+                    break;
+                case MotionEvent.ACTION_UP:  // fall through
+                case MotionEvent.ACTION_CANCEL:
+                    showFloatingToolbar();
+            }
+        }
+    }
+
+    private void hideFloatingToolbar() {
+        if (mSelectionActionMode != null) {
+            mTextView.removeCallbacks(mShowFloatingToolbar);
+            // Delay the "hide" a little bit just in case a "show" will happen almost immediately.
+            mTextView.postDelayed(mHideFloatingToolbar, 100);
+        }
+    }
+
+    private void showFloatingToolbar() {
+        if (mSelectionActionMode != null) {
+            mTextView.removeCallbacks(mHideFloatingToolbar);
+            // Delay "show" so it doesn't interfere with click confirmations
+            // or double-clicks that could "dismiss" the floating toolbar.
+            int delay = ViewConfiguration.getDoubleTapTimeout();
+            mTextView.postDelayed(mShowFloatingToolbar, delay);
+        }
+    }
+
     public void beginBatchEdit() {
         mInBatchEditControllers = true;
         final InputMethodState ims = mInputMethodState;
@@ -3661,6 +3715,8 @@
 
         @Override
         public boolean onTouchEvent(MotionEvent ev) {
+            updateFloatingToolbarVisibility(ev);
+
             switch (ev.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN: {
                     startTouchUpFilter(getCurrentCursorOffset());
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5acd79f..a93e7ef 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -24,6 +24,7 @@
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
 import android.annotation.XmlRes;
+import android.app.Activity;
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Context;
@@ -1465,16 +1466,22 @@
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (requestCode == PROCESS_TEXT_REQUEST_CODE) {
-            CharSequence result = data != null
-                    ? data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT)
-                    : "";
-            if (isTextEditable()) {
-                replaceSelectionWithText(result);
-            } else {
-                if (result.length() > 0) {
-                    Toast.makeText(getContext(), String.valueOf(result), Toast.LENGTH_LONG).show();
+            if (resultCode == Activity.RESULT_OK && data != null) {
+                CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT);
+                if (result != null) {
+                    if (isTextEditable()) {
+                        replaceSelectionWithText(result);
+                    } else {
+                        if (result.length() > 0) {
+                            Toast.makeText(getContext(), String.valueOf(result), Toast.LENGTH_LONG)
+                                .show();
+                        }
+                    }
                 }
             }
+            if (mEditor.hasSelectionController()) {
+                mEditor.startSelectionActionModeWithSelection();
+            }
         }
     }
 
@@ -9279,7 +9286,6 @@
 
     void replaceSelectionWithText(CharSequence text) {
         ((Editable) mText).replace(getSelectionStart(), getSelectionEnd(), text);
-        mEditor.startSelectionActionModeWithSelection();
     }
 
     /**
diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java
index 65dc743..b9a75d3 100644
--- a/core/java/com/android/internal/logging/MetricsConstants.java
+++ b/core/java/com/android/internal/logging/MetricsConstants.java
@@ -208,6 +208,7 @@
     public static final int APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
     public static final int APPLICATIONS_HIGH_POWER_APPS = 184;
     public static final int FUELGAUGE_HIGH_POWER_DETAILS = 185;
+    public static final int APPLICATIONS_MANAGE_ASSIST = 186;
 
     //aliases
     public static final int DEVICEINFO_STORAGE = DEVICEINFO_MEMORY;
diff --git a/core/java/com/android/internal/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java
index 1bcc7a0..58ae853 100644
--- a/core/java/com/android/internal/util/ScreenShapeHelper.java
+++ b/core/java/com/android/internal/util/ScreenShapeHelper.java
@@ -33,16 +33,4 @@
         }
         return 0;
     }
-
-    /**
-     * Get whether a device has has a round screen.
-     */
-    public static boolean getWindowIsRound(Resources resources) {
-        if (IS_EMULATOR) {
-            return SystemProperties.getBoolean(ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false);
-        } else {
-            return resources.getBoolean(
-                    com.android.internal.R.bool.config_windowIsRound);
-        }
-    }
 }
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index c3f4da7..8402cc0 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -30,6 +30,9 @@
 
 public class FloatingActionMode extends ActionMode {
 
+    private static final int MAX_SNOOZE_TIME = 3000;
+    private static final int MOVING_HIDE_DELAY = 300;
+
     private final Context mContext;
     private final ActionMode.Callback2 mCallback;
     private final MenuBuilder mMenu;
@@ -38,12 +41,26 @@
     private final Rect mPreviousContentRectOnWindow;
     private final int[] mViewPosition;
     private final View mOriginatingView;
+
+    private final Runnable mMovingOff = new Runnable() {
+        public void run() {
+            mFloatingToolbarVisibilityHelper.setMoving(false);
+        }
+    };
+
+    private final Runnable mSnoozeOff = new Runnable() {
+        public void run() {
+            mFloatingToolbarVisibilityHelper.setSnoozed(false);
+        }
+    };
+
     private FloatingToolbar mFloatingToolbar;
+    private FloatingToolbarVisibilityHelper mFloatingToolbarVisibilityHelper;
 
     public FloatingActionMode(
             Context context, ActionMode.Callback2 callback, View originatingView) {
-        mContext = context;
-        mCallback = callback;
+        mContext = Preconditions.checkNotNull(context);
+        mCallback = Preconditions.checkNotNull(callback);
         mMenu = new MenuBuilder(context).setDefaultShowAsAction(
                 MenuItem.SHOW_AS_ACTION_IF_ROOM);
         setType(ActionMode.TYPE_FLOATING);
@@ -51,7 +68,8 @@
         mContentRectOnWindow = new Rect();
         mPreviousContentRectOnWindow = new Rect();
         mViewPosition = new int[2];
-        mOriginatingView = originatingView;
+        mOriginatingView = Preconditions.checkNotNull(originatingView);
+        mOriginatingView.getLocationInWindow(mViewPosition);
     }
 
     public void setFloatingToolbar(FloatingToolbar floatingToolbar) {
@@ -63,6 +81,7 @@
                         return mCallback.onActionItemClicked(FloatingActionMode.this, item);
                     }
                 });
+        mFloatingToolbarVisibilityHelper = new FloatingToolbarVisibilityHelper(mFloatingToolbar);
     }
 
     @Override
@@ -82,7 +101,7 @@
 
     @Override
     public void invalidate() {
-        Preconditions.checkNotNull(mFloatingToolbar);
+        checkToolbarInitialized();
         mCallback.onPrepareActionMode(this, mMenu);
         mFloatingToolbar.updateLayout();
         invalidateContentRect();
@@ -90,32 +109,57 @@
 
     @Override
     public void invalidateContentRect() {
-        Preconditions.checkNotNull(mFloatingToolbar);
+        checkToolbarInitialized();
         mCallback.onGetContentRect(this, mOriginatingView, mContentRect);
         repositionToolbar();
     }
 
     public void updateViewLocationInWindow() {
-        Preconditions.checkNotNull(mFloatingToolbar);
+        checkToolbarInitialized();
         mOriginatingView.getLocationInWindow(mViewPosition);
         repositionToolbar();
     }
 
     private void repositionToolbar() {
+        checkToolbarInitialized();
         mContentRectOnWindow.set(
                 mContentRect.left + mViewPosition[0],
                 mContentRect.top + mViewPosition[1],
                 mContentRect.right + mViewPosition[0],
                 mContentRect.bottom + mViewPosition[1]);
         if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) {
+            if (!mPreviousContentRectOnWindow.isEmpty()) {
+                notifyContentRectMoving();
+            }
             mFloatingToolbar.setContentRect(mContentRectOnWindow);
             mFloatingToolbar.updateLayout();
         }
         mPreviousContentRectOnWindow.set(mContentRectOnWindow);
     }
 
+    private void notifyContentRectMoving() {
+        mOriginatingView.removeCallbacks(mMovingOff);
+        mFloatingToolbarVisibilityHelper.setMoving(true);
+        mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
+    }
+
+    @Override
+    public void snooze(int snoozeTime) {
+        checkToolbarInitialized();
+        snoozeTime = Math.min(MAX_SNOOZE_TIME, snoozeTime);
+        mOriginatingView.removeCallbacks(mSnoozeOff);
+        if (snoozeTime <= 0) {
+            mSnoozeOff.run();
+        } else {
+            mFloatingToolbarVisibilityHelper.setSnoozed(true);
+            mOriginatingView.postDelayed(mSnoozeOff, snoozeTime);
+        }
+    }
+
     @Override
     public void finish() {
+        checkToolbarInitialized();
+        reset();
         mCallback.onDestroyActionMode(this);
     }
 
@@ -144,4 +188,56 @@
         return new MenuInflater(mContext);
     }
 
+    /**
+     * @throws IlllegalStateException
+     */
+    private void checkToolbarInitialized() {
+        Preconditions.checkState(mFloatingToolbar != null);
+        Preconditions.checkState(mFloatingToolbarVisibilityHelper != null);
+    }
+
+    private void reset() {
+        mOriginatingView.removeCallbacks(mMovingOff);
+        mOriginatingView.removeCallbacks(mSnoozeOff);
+    }
+
+
+    /**
+     * A helper that shows/hides the floating toolbar depending on certain states.
+     */
+    private static final class FloatingToolbarVisibilityHelper {
+
+        private final FloatingToolbar mToolbar;
+
+        private boolean mSnoozed;
+        private boolean mMoving;
+        private boolean mOutOfBounds;
+
+        public FloatingToolbarVisibilityHelper(FloatingToolbar toolbar) {
+            mToolbar = Preconditions.checkNotNull(toolbar);
+        }
+
+        public void setSnoozed(boolean snoozed) {
+            mSnoozed = snoozed;
+            updateToolbarVisibility();
+        }
+
+        public void setMoving(boolean moving) {
+            mMoving = moving;
+            updateToolbarVisibility();
+        }
+
+        public void setOutOfBounds(boolean outOfBounds) {
+            mOutOfBounds = outOfBounds;
+            updateToolbarVisibility();
+        }
+
+        private void updateToolbarVisibility() {
+            if (mSnoozed || mMoving || mOutOfBounds) {
+                mToolbar.hide();
+            } else if (mToolbar.isHidden()) {
+                mToolbar.show();
+            }
+        }
+    }
 }
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index a80abce5..f485460 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -16,14 +16,12 @@
 
 package com.android.server.backup;
 
-import android.app.ActivityManagerNative;
 import android.app.IWallpaperManager;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupAgentHelper;
 import android.app.backup.FullBackup;
 import android.app.backup.FullBackupDataOutput;
-import android.app.backup.RecentsBackupHelper;
 import android.app.backup.WallpaperBackupHelper;
 import android.content.Context;
 import android.os.Environment;
@@ -45,7 +43,6 @@
     // Names of the helper tags within the dataset.  Changing one of these names will
     // break the ability to restore from datasets that predate the change.
     private static final String WALLPAPER_HELPER = "wallpaper";
-    private static final String RECENTS_HELPER = "recents";
     private static final String SYNC_SETTINGS_HELPER = "account_sync_settings";
     private static final String PREFERRED_HELPER = "preferred_activities";
     private static final String NOTIFICATION_HELPER = "notifications";
@@ -92,7 +89,6 @@
             }
         }
         addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this, files, keys));
-        addHelper(RECENTS_HELPER, new RecentsBackupHelper(this));
         addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
         addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
         addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
@@ -127,7 +123,6 @@
         addHelper("system_files", new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE },
                 new String[] { WALLPAPER_IMAGE_KEY} ));
-        addHelper(RECENTS_HELPER, new RecentsBackupHelper(this));
         addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
         addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
         addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
@@ -200,13 +195,4 @@
             }
         }
     }
-
-    @Override
-    public void onRestoreFinished() {
-        try {
-            ActivityManagerNative.getDefault().systemBackupRestored();
-        } catch (RemoteException e) {
-            // Not possible since this code is running in the system process.
-        }
-    }
 }
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 2785c48..04b9a95 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1,5 +1,4 @@
 #define LOG_TAG "Bitmap"
-
 #include "Bitmap.h"
 
 #include "Paint.h"
@@ -23,6 +22,10 @@
 #include "core_jni_helpers.h"
 
 #include <jni.h>
+#include <memory>
+#include <string>
+#include <sys/mman.h>
+#include <cutils/ashmem.h>
 
 namespace android {
 
@@ -135,6 +138,17 @@
     mPixelRef->unref();
 }
 
+Bitmap::Bitmap(void* address, int fd,
+            const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
+        : mPixelStorageType(PixelStorageType::Ashmem) {
+    mPixelStorage.ashmem.address = address;
+    mPixelStorage.ashmem.fd = fd;
+    mPixelStorage.ashmem.size = ashmem_get_size_region(fd);
+    mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
+    // Note: this will trigger a call to onStrongRefDestroyed(), but
+    // we want the pixel ref to have a ref count of 0 at this point
+    mPixelRef->unref();
+}
 Bitmap::~Bitmap() {
     doFreePixels();
 }
@@ -156,6 +170,10 @@
         mPixelStorage.external.freeFunc(mPixelStorage.external.address,
                 mPixelStorage.external.context);
         break;
+    case PixelStorageType::Ashmem:
+        munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
+        close(mPixelStorage.ashmem.fd);
+        break;
     case PixelStorageType::Java:
         JNIEnv* env = jniEnv();
         LOG_ALWAYS_FATAL_IF(mPixelStorage.java.jstrongRef,
@@ -179,6 +197,15 @@
     mPixelRef->setHasHardwareMipMap(hasMipMap);
 }
 
+int Bitmap::getAshmemFd() const {
+    switch (mPixelStorageType) {
+    case PixelStorageType::Ashmem:
+        return mPixelStorage.ashmem.fd;
+    default:
+        return -1;
+    }
+}
+
 const SkImageInfo& Bitmap::info() const {
     assertValid();
     return mPixelRef->info();
@@ -274,6 +301,7 @@
         LOG_ALWAYS_FATAL("Cannot pin invalid pixels!");
         break;
     case PixelStorageType::External:
+    case PixelStorageType::Ashmem:
         // Nothing to do
         break;
     case PixelStorageType::Java: {
@@ -296,6 +324,7 @@
         LOG_ALWAYS_FATAL("Cannot unpin invalid pixels!");
         break;
     case PixelStorageType::External:
+    case PixelStorageType::Ashmem:
         // Don't need to do anything
         break;
     case PixelStorageType::Java: {
@@ -690,6 +719,21 @@
             getPremulBitmapCreateFlags(isMutable));
 }
 
+static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
+    SkBitmap src;
+    reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
+    SkBitmap result;
+
+    AshmemPixelAllocator allocator(env);
+    if (!src.copyTo(&result, &allocator)) {
+        return NULL;
+    }
+    Bitmap* bitmap = allocator.getStorageObjAndReset();
+    bitmap->peekAtPixelRef()->setImmutable();
+    jobject ret = GraphicsJNI::createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
+    return ret;
+}
+
 static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
     LocalScopedBitmap bitmap(bitmapHandle);
     bitmap->detachFromJava();
@@ -898,34 +942,76 @@
         }
     }
 
-    android::Bitmap* nativeBitmap = GraphicsJNI::allocateJavaPixelRef(env, bitmap.get(), ctable);
-    if (!nativeBitmap) {
+    int fd = p->readFileDescriptor();
+    int dupFd = dup(fd);
+    if (dupFd < 0) {
         SkSafeUnref(ctable);
+        doThrowRE(env, "Could not dup parcel fd.");
         return NULL;
     }
 
+    bool readOnlyMapping = !isMutable;
+    Bitmap* nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(),
+        ctable, dupFd, readOnlyMapping);
     SkSafeUnref(ctable);
-
-    size_t size = bitmap->getSize();
-
-    android::Parcel::ReadableBlob blob;
-    android::status_t status = p->readBlob(size, &blob);
-    if (status) {
-        nativeBitmap->detachFromJava();
-        doThrowRE(env, "Could not read bitmap from parcel blob.");
+    if (!nativeBitmap) {
+        close(dupFd);
+        doThrowRE(env, "Could not allocate ashmem pixel ref.");
         return NULL;
     }
-
-    bitmap->lockPixels();
-    memcpy(bitmap->getPixels(), blob.data(), size);
-    bitmap->unlockPixels();
-
-    blob.release();
+    bitmap->pixelRef()->setImmutable();
 
     return GraphicsJNI::createBitmap(env, nativeBitmap,
             getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
 }
 
+class Ashmem {
+public:
+    Ashmem(size_t sz, bool removeWritePerm) : mSize(sz) {
+        int fd = -1;
+        void *addr = nullptr;
+
+        // Create new ashmem region with read/write priv
+        fd = ashmem_create_region("bitmap", sz);
+        if (fd < 0) {
+            goto error;
+        }
+        addr = mmap(nullptr, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+        if (addr == MAP_FAILED) {
+            goto error;
+        }
+        // If requested, remove the ability to make additional writeable to
+        // this memory.
+        if (removeWritePerm) {
+            if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
+                goto error;
+            }
+        }
+        mFd = fd;
+        mPtr = addr;
+        return;
+error:
+        if (fd >= 0) {
+            close(fd);
+        }
+        if (addr) {
+            munmap(addr, sz);
+        }
+    }
+    ~Ashmem() {
+        if (mPtr) {
+            close(mFd);
+            munmap(mPtr, mSize);
+        }
+    }
+    void *getPtr() const { return mPtr; }
+    int getFd() const { return mFd; }
+private:
+    int mFd = -1;
+    int mSize;
+    void* mPtr = nullptr;
+};
+
 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
                                      jlong bitmapHandle,
                                      jboolean isMutable, jint density,
@@ -937,7 +1023,9 @@
 
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
     SkBitmap bitmap;
-    reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap);
+
+    android::Bitmap* androidBitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
+    androidBitmap->getSkBitmap(&bitmap);
 
     p->writeInt32(isMutable);
     p->writeInt32(bitmap.colorType());
@@ -959,25 +1047,26 @@
         }
     }
 
-    size_t size = bitmap.getSize();
-
-    android::Parcel::WritableBlob blob;
-    android::status_t status = p->writeBlob(size, &blob);
-    if (status) {
-        doThrowRE(env, "Could not write bitmap to parcel blob.");
-        return JNI_FALSE;
-    }
-
-    bitmap.lockPixels();
-    const void* pSrc =  bitmap.getPixels();
-    if (pSrc == NULL) {
-        memset(blob.data(), 0, size);
+    bool ashmemSrc = androidBitmap->getAshmemFd() >= 0;
+    if (ashmemSrc && !isMutable) {
+        p->writeDupFileDescriptor(androidBitmap->getAshmemFd());
     } else {
-        memcpy(blob.data(), pSrc, size);
-    }
-    bitmap.unlockPixels();
+        Ashmem dstAshmem(bitmap.getSize(), !isMutable);
+        if (!dstAshmem.getPtr()) {
+            doThrowRE(env, "Could not allocate ashmem for new bitmap.");
+            return JNI_FALSE;
+        }
 
-    blob.release();
+        bitmap.lockPixels();
+        const void* pSrc = bitmap.getPixels();
+        if (pSrc == NULL) {
+            memset(dstAshmem.getPtr(), 0, bitmap.getSize());
+        } else {
+            memcpy(dstAshmem.getPtr(), pSrc, bitmap.getSize());
+        }
+        bitmap.unlockPixels();
+        p->writeDupFileDescriptor(dstAshmem.getFd());
+    }
     return JNI_TRUE;
 }
 
@@ -1193,6 +1282,8 @@
         (void*)Bitmap_creator },
     {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
         (void*)Bitmap_copy },
+    {   "nativeCopyAshmem",         "(J)Landroid/graphics/Bitmap;",
+        (void*)Bitmap_copyAshmem },
     {   "nativeDestructor",         "(J)V", (void*)Bitmap_destructor },
     {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
     {   "nativeReconfigure",        "(JIIIIZ)V", (void*)Bitmap_reconfigure },
diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h
index efeb898..95b5fae 100644
--- a/core/jni/android/graphics/Bitmap.h
+++ b/core/jni/android/graphics/Bitmap.h
@@ -29,6 +29,7 @@
     Invalid,
     External,
     Java,
+    Ashmem,
 };
 
 class WrappedPixelRef;
@@ -50,6 +51,8 @@
             const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
     Bitmap(void* address, void* context, FreeFunc freeFunc,
             const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
+    Bitmap(void* address, int fd, const SkImageInfo& info, size_t rowBytes,
+            SkColorTable* ctable);
 
     const SkImageInfo& info() const;
 
@@ -76,6 +79,7 @@
 
     bool hasHardwareMipMap();
     void setHasHardwareMipMap(bool hasMipMap);
+    int getAshmemFd() const;
 
 private:
     friend class WrappedPixelRef;
@@ -104,6 +108,11 @@
             FreeFunc freeFunc;
         } external;
         struct {
+            void* address;
+            int fd;
+            size_t size;
+        } ashmem;
+        struct {
             JavaVM* jvm;
             jweak jweakRef;
             jbyteArray jstrongRef;
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 1c6f7de..ff22ef3 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -1,5 +1,8 @@
 #define LOG_TAG "GraphicsJNI"
 
+#include <unistd.h>
+#include <sys/mman.h>
+
 #include "jni.h"
 #include "JNIHelp.h"
 #include "GraphicsJNI.h"
@@ -10,6 +13,7 @@
 #include "SkMath.h"
 #include "SkRegion.h"
 #include <android_runtime/AndroidRuntime.h>
+#include <cutils/ashmem.h>
 
 #include <Caches.h>
 #include <TextureCache.h>
@@ -572,6 +576,82 @@
     return true;
 }
 
+android::Bitmap* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+                                                     SkColorTable* ctable) {
+    int fd;
+
+    const SkImageInfo& info = bitmap->info();
+    if (info.fColorType == kUnknown_SkColorType) {
+        doThrowIAE(env, "unknown bitmap configuration");
+        return nullptr;
+    }
+
+    size_t size;
+    if (!computeAllocationSize(*bitmap, &size)) {
+        return nullptr;
+    }
+
+    // we must respect the rowBytes value already set on the bitmap instead of
+    // attempting to compute our own.
+    const size_t rowBytes = bitmap->rowBytes();
+
+    // Create new ashmem region with read/write priv
+    fd = ashmem_create_region("bitmap", size);
+    if (fd < 0) {
+        return nullptr;
+    }
+
+    void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if (addr == MAP_FAILED) {
+        close(fd);
+        return nullptr;
+    }
+
+    if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
+        munmap(addr, size);
+        close(fd);
+        return nullptr;
+    }
+
+    android::Bitmap* wrapper = new android::Bitmap(addr, fd, info, rowBytes, ctable);
+    wrapper->getSkBitmap(bitmap);
+    // since we're already allocated, we lockPixels right away
+    // HeapAllocator behaves this way too
+    bitmap->lockPixels();
+
+    return wrapper;
+}
+
+android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+                                                SkColorTable* ctable, int fd, bool readOnly) {
+    int flags;
+
+    const SkImageInfo& info = bitmap->info();
+    if (info.fColorType == kUnknown_SkColorType) {
+        doThrowIAE(env, "unknown bitmap configuration");
+        return nullptr;
+    }
+
+    // Create new ashmem region with read/write priv
+    flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE);
+    void* addr = mmap(NULL, ashmem_get_size_region(fd), flags, MAP_SHARED, fd, 0);
+    if (addr == MAP_FAILED) {
+        return nullptr;
+    }
+
+    // we must respect the rowBytes value already set on the bitmap instead of
+    // attempting to compute our own.
+    const size_t rowBytes = bitmap->rowBytes();
+
+    android::Bitmap* wrapper = new android::Bitmap(addr, fd, info, rowBytes, ctable);
+    wrapper->getSkBitmap(bitmap);
+    // since we're already allocated, we lockPixels right away
+    // HeapAllocator behaves this way too
+    bitmap->lockPixels();
+
+    return wrapper;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env) {
@@ -594,6 +674,25 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+AshmemPixelAllocator::AshmemPixelAllocator(JNIEnv *env) {
+    LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mJavaVM) != JNI_OK,
+            "env->GetJavaVM failed");
+}
+
+AshmemPixelAllocator::~AshmemPixelAllocator() {
+    if (mStorage) {
+        mStorage->detachFromJava();
+    }
+}
+
+bool AshmemPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
+    JNIEnv* env = vm2env(mJavaVM);
+    mStorage = GraphicsJNI::allocateAshmemPixelRef(env, bitmap, ctable);
+    return mStorage != nullptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 static jclass make_globalref(JNIEnv* env, const char classname[])
 {
     jclass c = env->FindClass(classname);
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index ef9c2a9..1938e85 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -95,6 +95,12 @@
     static android::Bitmap* allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
             SkColorTable* ctable);
 
+    static android::Bitmap* allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+            SkColorTable* ctable);
+
+    static android::Bitmap* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+            SkColorTable* ctable, int fd, bool readOnly);
+
     /**
      * Given a bitmap we natively allocate a memory block to store the contents
      * of that bitmap.  The memory is then attached to the bitmap via an
@@ -138,6 +144,23 @@
     android::Bitmap* mStorage = nullptr;
 };
 
+class AshmemPixelAllocator : public SkBitmap::Allocator {
+public:
+    AshmemPixelAllocator(JNIEnv* env);
+    ~AshmemPixelAllocator();
+    virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
+    android::Bitmap* getStorageObjAndReset() {
+        android::Bitmap* result = mStorage;
+        mStorage = NULL;
+        return result;
+    };
+
+private:
+    JavaVM* mJavaVM;
+    android::Bitmap* mStorage = nullptr;
+};
+
+
 enum JNIAccess {
     kRO_JNIAccess,
     kRW_JNIAccess
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index cf02e39..3bab2df 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -212,10 +212,14 @@
 
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
 
-    SkRegion* region = new SkRegion;
-    size_t size = p->readInt32();
-    size_t actualSize = region->readFromMemory(p->readInplace(size), size);
+    const size_t size = p->readInt32();
+    const void* regionData = p->readInplace(size);
+    if (regionData == nullptr) {
+        return 0;
+    }
 
+    SkRegion* region = new SkRegion;
+    size_t actualSize = region->readFromMemory(regionData, size);
     if (size != actualSize) {
         delete region;
         return 0;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 74a9e4e..dca04f5 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -615,6 +615,10 @@
 
     const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
 
+    // Constants duplicated from Java class android.content.res.Configuration.
+    static const jint kScreenLayoutRoundMask = 0x300;
+    static const jint kScreenLayoutRoundShift = 8;
+
     config.mcc = (uint16_t)mcc;
     config.mnc = (uint16_t)mnc;
     config.orientation = (uint8_t)orientation;
@@ -632,6 +636,13 @@
     config.uiMode = (uint8_t)uiMode;
     config.sdkVersion = (uint16_t)sdkVersion;
     config.minorVersion = 0;
+
+    // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
+    // in C++. We must extract the round qualifier out of the Java screenLayout and put it
+    // into screenLayout2.
+    config.screenLayout2 =
+            (uint8_t)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
+
     am->setConfiguration(config, locale8);
 
     if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 608d718..595f9f0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -898,7 +898,9 @@
         android:label="@string/permlab_changeWimaxState"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows applications to act as network scorers. @hide @SystemApi-->
+    <!--@SystemApi Allows applications to the the local WiFi and Bluetooth MAC address.
+        @hide
+    -->
     <permission android:name="android.permission.SCORE_NETWORKS"
         android:protectionLevel="signature|system" />
 
@@ -2447,6 +2449,10 @@
     <permission android:name="android.permission.KILL_UID"
                 android:protectionLevel="signature" />
 
+    <!-- Allows applications to act as network scorers. @hide @SystemApi-->
+    <permission android:name="android.permission.LOCAL_MAC_ADDRESS"
+                android:protectionLevel="signature" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index d292d4e..a8d2ee3 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -132,7 +132,7 @@
             android:ellipsize="end"
             android:visibility="gone"
             android:layout_weight="1"
-            android:text="@android:string/ellipsis"
+            android:text="@android:string/notification_inbox_ellipsis"
             />
         <FrameLayout
             android:id="@+id/inbox_end_pad"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 84e4ca9..f790d74 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -423,11 +423,17 @@
          point on the move. A value of 0 means no periodic scans will be used in the framework. -->
     <integer translatable="false" name="config_wifi_framework_scan_interval">300000</integer>
 
-    <!-- Integer indicating disconnect mode scan interval in milliseconds -->
-    <integer translatable="false" name="config_wifi_disconnected_scan_interval">15000</integer>
+    <!-- Integer indicating disconnect mode short scan interval in milliseconds -->
+    <integer translatable="false" name="config_wifi_disconnected_short_scan_interval">15000</integer>
 
-    <!-- Integer indicating associated partial scan interval in milliseconds -->
-    <integer translatable="false" name="config_wifi_framework_associated_scan_interval">20000</integer>
+    <!-- Integer indicating disconnect mode long scan interval in milliseconds -->
+    <integer translatable="false" name="config_wifi_disconnected_long_scan_interval">120000</integer>
+
+    <!-- Integer indicating associated partial scan short interval in milliseconds -->
+    <integer translatable="false" name="config_wifi_associated_short_scan_interval">20000</integer>
+
+    <!-- Integer indicating associated partial scan long interval in milliseconds -->
+    <integer translatable="false" name="config_wifi_associated_long_scan_interval">180000</integer>
 
     <!-- Integer indicating associated full scan backoff, representing a fraction: xx/8 -->
     <integer translatable="false" name="config_wifi_framework_associated_full_scan_backoff">12</integer>
@@ -2151,4 +2157,10 @@
          format is UMTS|LTE|... -->
     <string translatable="false" name="config_radio_access_family"></string>
 
+    <!-- Whether the main built-in display is round. This will affect
+         Configuration.screenLayout's SCREENLAYOUT_ROUND_MASK flags for Configurations on the
+         main built-in display. Change this in device-specific overlays.
+         Defaults to the older, deprecated config_windowIsRound already used in
+         some existing device-specific resource overlays. -->
+    <bool name="config_mainBuiltInDisplayIsRound">@bool/config_windowIsRound</bool>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0e6b2df..2b8665e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4127,4 +4127,8 @@
     <!-- Content description for the button that closes the floating toolbar overflow. [CHAR LIMIT=NONE] -->
     <string name="floating_toolbar_close_overflow_description">Close overflow</string>
 
+    <!-- Ellipsis character to appear in notification templates, e.g.
+         notification_template_material_inbox.xml.
+         DO NOT TRANSLATE -->
+    <string name="notification_inbox_ellipsis">\u2026</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 64e3964..6124b5b 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -294,7 +294,6 @@
   <java-symbol type="bool" name="config_wifi_batched_scan_supported" />
   <java-symbol type="bool" name="config_enableMultiUserUI"/>
   <java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
-  <java-symbol type="bool" name="config_windowIsRound" />
   <java-symbol type="bool" name="config_hasRecents" />
   <java-symbol type="bool" name="config_windowShowCircularMask" />
   <java-symbol type="bool" name="config_windowEnableCircularEmulatorDisplayOverlay" />
@@ -310,7 +309,10 @@
   <java-symbol type="integer" name="config_wifi_framework_current_association_hysteresis_low" />
   <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" />
   <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_factor" />
-  <java-symbol type="integer" name="config_wifi_framework_associated_scan_interval" />
+  <java-symbol type="integer" name="config_wifi_disconnected_short_scan_interval" />
+  <java-symbol type="integer" name="config_wifi_disconnected_long_scan_interval" />
+  <java-symbol type="integer" name="config_wifi_associated_short_scan_interval" />
+  <java-symbol type="integer" name="config_wifi_associated_long_scan_interval" />
   <java-symbol type="integer" name="config_wifi_framework_associated_full_scan_backoff" />
   <java-symbol type="integer" name="config_wifi_framework_associated_full_scan_max_interval" />
   <java-symbol type="integer" name="config_wifi_framework_associated_full_scan_max_total_dwell_time" />
@@ -380,7 +382,6 @@
   <java-symbol type="integer" name="config_shortPressOnSleepBehavior" />
   <java-symbol type="integer" name="config_wifi_framework_scan_interval" />
   <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
-  <java-symbol type="integer" name="config_wifi_disconnected_scan_interval" />
   <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
   <java-symbol type="bool" name="config_wifi_hal_pno_enable" />
   <java-symbol type="integer" name="db_connection_pool_size" />
@@ -443,8 +444,6 @@
   <java-symbol type="string" name="app_running_notification_text" />
   <java-symbol type="string" name="delete" />
   <java-symbol type="string" name="deleteText" />
-  <java-symbol type="string" name="ellipsis_two_dots" />
-  <java-symbol type="string" name="ellipsis" />
   <java-symbol type="string" name="grant_permissions_header_text" />
   <java-symbol type="string" name="list_delimeter" />
   <java-symbol type="string" name="menu_delete_shortcut_label" />
@@ -2278,4 +2277,6 @@
   <java-symbol type="bool" name="config_supportDoubleTapWake" />
   <java-symbol type="drawable" name="ic_perm_device_info" />
   <java-symbol type="string" name="config_radio_access_family" />
+  <java-symbol type="string" name="notification_inbox_ellipsis" />
+  <java-symbol type="bool" name="config_mainBuiltInDisplayIsRound" />
 </resources>
diff --git a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
index 0634281..a7bebad 100644
--- a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ b/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
@@ -26,9 +26,11 @@
 import libcore.util.HexEncoding;
 
 import java.net.InetAddress;
+import java.net.Inet4Address;
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.Arrays;
 import junit.framework.TestCase;
 
 
@@ -133,7 +135,7 @@
     public static final byte[] RTM_GETNEIGH_RESPONSE =
             HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
 
-    public void testParseRtNetlinkNeighborRtmDelNeigh() {
+    public void testParseRtmDelNeigh() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
         final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
@@ -159,7 +161,7 @@
         assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
     }
 
-    public void testParseRtNetlinkNeighborRtmNewNeigh() {
+    public void testParseRtmNewNeigh() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
         final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
@@ -185,7 +187,7 @@
         assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
     }
 
-    public void testParseRtNetlinkNeighborRtmGetNeighResponse() {
+    public void testParseRtmGetNeighResponse() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
 
@@ -208,4 +210,48 @@
         // TODO: add more detailed spot checks.
         assertEquals(14, messageCount);
     }
+
+    public void testCreateRtmNewNeighMessage() {
+        final int seqNo = 2635;
+        final int ifIndex = 14;
+        final byte[] llAddr =
+                new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6 };
+
+        // Hexadecimal representation of our created packet.
+        final String expectedNewNeighHex =
+                // struct nlmsghdr
+                "30000000" +     // length = 48
+                "1c00" +         // type = 28 (RTM_NEWNEIGH)
+                "0101" +         // flags (NLM_F_REQUEST | NLM_F_REPLACE)
+                "4b0a0000" +     // seqno
+                "00000000" +     // pid (0 == kernel)
+                // struct ndmsg
+                "02" +           // family
+                "00" +           // pad1
+                "0000" +         // pad2
+                "0e000000" +     // interface index (14)
+                "0800" +         // NUD state (0x08 == NUD_DELAY)
+                "00" +           // flags
+                "00" +           // type
+                // struct nlattr: NDA_DST
+                "0800" +         // length = 8
+                "0100" +         // type (1 == NDA_DST, for neighbor messages)
+                "7f000001" +     // IPv4 address (== 127.0.0.1)
+                // struct nlattr: NDA_LLADDR
+                "0a00" +         // length = 10
+                "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
+                "010203040506" + // MAC Address (== 01:02:03:04:05:06)
+                "0000";          // padding, for 4 byte alignment
+        final byte[] expectedNewNeigh =
+                HexEncoding.decode(expectedNewNeighHex.toCharArray(), false);
+
+        final byte[] bytes = RtNetlinkNeighborMessage.newNewNeighborMessage(
+            seqNo, Inet4Address.LOOPBACK, StructNdMsg.NUD_DELAY, ifIndex, llAddr);
+        if (!Arrays.equals(expectedNewNeigh, bytes)) {
+            assertEquals(expectedNewNeigh.length, bytes.length);
+            for (int i = 0; i < Math.min(expectedNewNeigh.length, bytes.length); i++) {
+                assertEquals(expectedNewNeigh[i], bytes[i]);
+            }
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index af6df1a..0b94f8b 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -16,9 +16,13 @@
 
 package android.widget;
 
+import android.app.Activity;
+import android.content.Intent;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.GetChars;
+import android.text.Selection;
+import android.text.Spannable;
 
 /**
  * TextViewTest tests {@link TextView}.
@@ -54,4 +58,66 @@
         assertEquals('o', c2[4]);
         assertEquals('\0', c2[5]);
     }
+
+    public void testProcessTextActivityResultNonEditable() {
+        TextView tv = new TextView(mContext);
+        CharSequence originalText = "This is some text.";
+        tv.setText(originalText, TextView.BufferType.SPANNABLE);
+        assertEquals(originalText, tv.getText().toString());
+        tv.setTextIsSelectable(true);
+        Selection.setSelection((Spannable) tv.getText(), 0, tv.getText().length());
+
+        CharSequence newText = "Text is replaced.";
+        Intent data = new Intent();
+        data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
+        tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, data);
+
+        // This is a TextView, which can't be modified. Hence no change should have been made.
+        assertEquals(originalText, tv.getText().toString());
+    }
+
+    public void testProcessTextActivityResultEditable() {
+        EditText tv = new EditText(mContext);
+        CharSequence originalText = "This is some text.";
+        tv.setText(originalText, TextView.BufferType.SPANNABLE);
+        assertEquals(originalText, tv.getText().toString());
+        tv.setTextIsSelectable(true);
+        Selection.setSelection(tv.getText(), 0, tv.getText().length());
+
+        CharSequence newText = "Text is replaced.";
+        Intent data = new Intent();
+        data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
+        tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, data);
+
+        assertEquals(newText, tv.getText().toString());
+    }
+
+    public void testProcessTextActivityResultCancel() {
+        EditText tv = new EditText(mContext);
+        CharSequence originalText = "This is some text.";
+        tv.setText(originalText, TextView.BufferType.SPANNABLE);
+        assertEquals(originalText, tv.getText().toString());
+        tv.setTextIsSelectable(true);
+        Selection.setSelection(tv.getText(), 0, tv.getText().length());
+
+        CharSequence newText = "Text is replaced.";
+        Intent data = new Intent();
+        data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
+        tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_CANCELED, data);
+
+        assertEquals(originalText, tv.getText().toString());
+    }
+
+    public void testProcessTextActivityNoData() {
+        EditText tv = new EditText(mContext);
+        CharSequence originalText = "This is some text.";
+        tv.setText(originalText, TextView.BufferType.SPANNABLE);
+        assertEquals(originalText, tv.getText().toString());
+        tv.setTextIsSelectable(true);
+        Selection.setSelection(tv.getText(), 0, tv.getText().length());
+
+        tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, null);
+
+        assertEquals(originalText, tv.getText().toString());
+    }
 }
diff --git a/docs/html/about/about_toc.cs b/docs/html/about/about_toc.cs
index b1357f2..a4bc4a5 100644
--- a/docs/html/about/about_toc.cs
+++ b/docs/html/about/about_toc.cs
@@ -1,11 +1,5 @@
 <ul id="nav">
 
-<li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot?>about/index.html">Welcome</a></div>
-    <ul>
-      <li><a href="<?cs var:toroot?>about/start.html">Get Started</a></li>
-    </ul>
-  </li>
   <li class="nav-section">
     <div class="nav-section-header"><a href="<?cs var:toroot ?>about/versions/lollipop.html"
               zh-tw-lang="Lollipop"
@@ -46,14 +40,20 @@
       </ul>
   </li>
 
-  <li class="nav-section">
+  <!-- <li class="nav-section">
     <div class="nav-section-header"><a href="<?cs var:toroot ?>about/versions/android-4.0-highlights.html">
       <span class="en">Ice Cream Sandwich</span></a></div>
       <ul>
         <li><a href="<?cs var:toroot ?>about/versions/android-4.0.3.html">Android 4.0.3 APIs</a></li>
         <li><a href="<?cs var:toroot ?>about/versions/android-4.0.html">Android 4.0 APIs</a> </li>
       </ul>
+  </li> -->
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs
+var:toroot?>about/android.html">About Android</a></div>
   </li>
+
   <li class="nav-section">
     <div class="nav-section-header empty"><a href="<?cs
 var:toroot?>about/dashboards/index.html">Dashboards</a></div>
diff --git a/docs/html/about/android.jd b/docs/html/about/android.jd
new file mode 100644
index 0000000..ad0ea7c
--- /dev/null
+++ b/docs/html/about/android.jd
@@ -0,0 +1,111 @@
+page.title=Android, the world's most popular mobile platform
+excludeFromSuggestions=true
+walkthru=0
+header.hide=0
+
+@jd:body
+
+
+<p>Android powers hundreds of millions of mobile devices in more than 190
+countries around the world. It's the largest installed base of any mobile platform
+and growing fast&mdash;every day another million users power up their
+Android devices for the first time and start looking for apps, games,
+and other digital content. </p>
+
+
+<p>Android gives you a world-class platform for creating apps and games for
+Android users everywhere, as well as an open marketplace for distributing
+to them instantly.</p>
+
+<h3>Global partnerships and large installed base</h3>
+
+<p>Building on the contributions of the open-source Linux community and more
+than 300 hardware, software, and carrier partners, Android has rapidly become
+the fastest-growing mobile OS.</p>
+
+<blockquote>Every day more than a million new Android devices are activated worldwide.</blockquote>
+
+<p>Android’s openness has made it a favorite for consumers and developers alike,
+driving strong growth in app consumption. Android users download more than 
+billions of apps and games from Google Play each month. </p>
+
+<p>With its partners, Android is continuously pushing the boundaries of hardware and software
+forward to bring new capabilities to users and developers. For developers, 
+Android innovation lets you build powerful, differentiated applications
+that use the latest mobile technologies.</p>
+
+<h3>Rapid innovation</h3>
+
+<p>Android is continuously pushing the boundaries of hardware and software
+forward, to bring new capabilities to users and developers. For developers, the
+rapid evolution of Android technology lets you stay in front with powerful,
+differentiated applications.</p>
+
+<p>Android gives you access to the latest technologies and innovations across a
+multitude of device form-factors, chipset architectures, and price points. From
+multicore processing and high-performance graphics to state-of-the-art sensors,
+vibrant touchscreens, and emerging mobile technologies.</p>
+
+<h3>Powerful development framework</h3>
+
+<blockquote>Easily optimize a single binary for phones, tablets, and other devices.</blockquote>
+
+<p>Android gives you everything you need to build best-in-class app experiences.
+It gives you a single application model that lets you deploy
+your apps broadly to hundreds of millions of users across a wide range of
+devices&mdash;from phones to tablets and beyond.</p>
+
+<p>Android also gives you tools for creating apps that look great and take
+advantage of the hardware capabilities available on each device. It
+automatically adapts your UI to look its best on each device, while giving you
+as much control as you want over your UI on different device
+types. </p> 
+
+<p>For example, you can create a single app binary that's optimized for
+both phone and tablet form factors. You declare your UI in lightweight sets of XML
+resources, one set for parts of the UI that are common to all form factors and
+other sets for optimzations specific to phones or tablets.
+At runtime, Android applies the correct resource sets based on its screen size,
+density, locale,
+and so on.</p>
+
+
+<p>To help you develop efficiently, the <a href="{@docRoot}tools/index.html">Android 
+    Developer Tools</a>
+offer a full Java IDE with advanced features for developing, debugging, and
+packaging Android apps. Using the IDE, you can develop on any available Android
+device or create virtual devices that emulate any hardware configuration.</p>
+
+<blockquote>1.5 billion downloads a month and growing. Get your apps in front
+of millions of users at Google's scale.</blockquote>
+
+<h3>Open marketplace for distributing your apps</h3>
+
+<p>Google Play is the premier marketplace for selling and distributing Android apps.
+When you publish an app on Google Play, you reach the huge installed base of
+Android.</p>
+
+<div style="float:left;margin-right:24px;margin-top:12px;">
+<img src="{@docRoot}images/gp-device.png">
+</div>
+
+<p>As an open marketplace, Google Play puts you in control of how you sell your
+products. You can publish whenever you want, as often as you want, and to the
+customers you want. You can distribute broadly to all markets and
+devices or focus on specific segments, devices, or ranges of hardware
+capabilities.</p>
+
+<p>You can monetize in the way that works best for your business&mdash;priced or
+free, with in-app products or subscriptions&mdash;for highest engagement and
+revenues. You also have complete control of the pricing for your apps
+and in-app products and can set or change prices in any supported currency at
+any time.<p>
+
+<p>Beyond growing your customer base, Google Play helps you build visibility and
+engagement across your apps and brand. As your apps rise in popularity, Google
+Play gives them higher placement in weekly "top" charts and rankings, and for
+the best apps promotional slots in curated collections.
+</p>
+
+<p>Preinstalled on hundreds of billions of Android devices around the world,
+Google Play can be a growth engine for your business.</p>
\ No newline at end of file
diff --git a/docs/html/about/versions/lollipop.jd b/docs/html/about/versions/lollipop.jd
index 1ad5d24..63a6fe9 100644
--- a/docs/html/about/versions/lollipop.jd
+++ b/docs/html/about/versions/lollipop.jd
@@ -3,47 +3,10 @@
 @jd:body
 
 
-
-
-
-
-
-
-
-
-  <div style="padding:0px 0px 0px 20px;float:right;margin:0 -10px 0 0">
-    <img src="{@docRoot}images/home/l-hero_2x.png" srcset="{@docRoot}images/home/l-hero.png 1x, {@docRoot}images/home/l-hero_2x.png 2x" width="460" height="300" >
-  </div>
-
-  <div class="landing-docs" style="float:right;clear:both;margin:68px 0 2em 3em;">
-  <div class="col-4 normal-links highlights" style="font-size:12px;">
-    <h3 id="thisd" >Key Developer Features</h3>
-    <ul style="list-style-type:none;">
-  <li><a href="#Material">Material design</a></li>
-  <li><a href="#Perf">Performance focus</a></li>
-  <li><a href="#Notifications">Notifications</a></li>
-  <li><a href="#TV">Your apps on the big screen</a></li>
-  <li><a href="#Documents">Document-centric apps</a></li>
-  <li><a href="#Connectivity">Advanced connectivity</a></li>
-  <li><a href="#Graphics">High-performance graphics</a></li>
-  <li><a href="#Audio">More powerful audio</a></li>
-  <li><a href="#Camera">Enhanced camera & video</a></li>
-  <li><a href="#Work">Android in the workplace</a></li>
-  <li><a href="#ScreenCapture">Screen capturing and sharing</a></li>
-  <li><a href="#Sensors">New types of sensors</a></li>
-  <li><a href="#WebView">Chromium WebView</a></li>
-  <li><a href="#Accessibility">Accessibility & input</a></li>
-  <li><a href="#Battery">Tools for battery-efficient apps</a></li>
-    </ul>
-  </div>
+<div style="float:right;">
+  <img src="{@docRoot}images/home/l-hero_2x.png" srcset="/images/home/l-hero.png 1x, /images/home/l-hero_2x.png 2x">
 </div>
 
-
-
-
-
-
-
 <p>Welcome to Android 5.0 Lollipop&mdash;the largest and most ambitious release for Android yet!</p>
 
 <p>This release is packed with new features for users and thousands of new APIs for developers. It extends Android even further, from phones, tablets, and wearables, to TVs and cars.</p>
@@ -55,42 +18,63 @@
 <a href="http://www.android.com/versions/lollipop-5-0/"
 >www.android.com</a>.</p>
 
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>Key developer features</h2>
+  <ol>
+      <ul style="list-style-type:none;">
+        <li><a href="#Material">Material design</a></li>
+        <li><a href="#Perf">Performance focus</a></li>
+        <li><a href="#Notifications">Notifications</a></li>
+        <li><a href="#TV">Your apps on the big screen</a></li>
+        <li><a href="#Documents">Document-centric apps</a></li>
+        <li><a href="#Connectivity">Advanced connectivity</a></li>
+        <li><a href="#Graphics">High-performance graphics</a></li>
+        <li><a href="#Audio">More powerful audio</a></li>
+        <li><a href="#Camera">Enhanced camera & video</a></li>
+        <li><a href="#Work">Android in the workplace</a></li>
+        <li><a href="#ScreenCapture">Screen capturing and sharing</a></li>
+        <li><a href="#Sensors">New types of sensors</a></li>
+        <li><a href="#WebView">Chromium WebView</a></li>
+        <li><a href="#Accessibility">Accessibility & input</a></li>
+        <li><a href="#Battery">Tools for battery-efficient apps</a></li>
+      </ol>
+</div>
+</div>
 
+<p class="note">
+  <strong>Note:</strong> The Android 5.1 Lollipop MR1 update is available with additional features
+  and fixes. For more information, see the
+  <a href="{@docRoot}about/versions/android-5.1.html">Android 5.1 API Overview</a>.
+</p>
 
 <h2 id="Material">Material design</h2>
 
 <p>Android 5.0 brings <a href="http://www.google.com/design/spec">Material design</a> to Android and gives you an expanded UI toolkit for integrating the new design patterns easily in your apps.  </p>
 
-
-
 <p>New <strong>3D views</strong> let you set a z-level to raise elements off of the view hierarchy and cast <strong>realtime shadows</strong>, even as they move.</p>
 
-
 <p>Built-in <strong>activity transitions</strong> take the user seamlessly from one state to another with beautiful, animated motion. The material theme adds transitions for your activities, including the ability to use <strong>shared visual elements</strong> across activities.</p>
 
-
-
-<div style="width:290px;margin-right:35px;float:left">
+<div style="float:left;max-width:280px;margin-right:1em;">
   <div class="framed-nexus5-port-span-5">
   <video class="play-on-hover" autoplay="">
-    <source src="/design/material/videos/ContactsAnim.mp4">
-    <source src="/design/videos/ContactsAnim.webm">
-    <source src="/design/videos/ContactsAnim.ogv">
+    <source src="{@docRoot}design/material/videos/ContactsAnim.mp4">
+    <source src="{@docRoot}design/videos/ContactsAnim.webm">
+    <source src="{@docRoot}design/videos/ContactsAnim.ogv">
   </video>
-  </div>
-  <div style="font-size:10pt;margin-left:20px;margin-bottom:30px">
+</div>
+  <p style="img-caption">
     <em>To replay the movie, click on the device screen</em>
-  </div>
+  </p>
 </div>
 
-
-<p>Ripple animations are available for buttons, checkboxes, and other touch controls in your app.
+<p>Ripple animations are available for buttons, checkboxes, and other touch controls in your app.</p>
 
 <p>You can also define vector drawables in XML and animate them in a variety of ways. Vector drawables scale without losing definition, so they are perfect for single-color in-app icons.</p>
 
 <p>A new system-managed processing thread called <strong>RenderThread</strong> keeps animations smooth even when there are delays in the main UI thread. </p>
 
-
 <h2 id="Perf">Performance focus</h2>
 
 <p>Android 5.0 provides a faster, smoother and more powerful computing experience.</p>
@@ -107,9 +91,12 @@
 
 <h2 id="Notifications">Notifications</h2>
 
+<div style="float:right;clear:left;margin:1em;">
+<img src="{@docRoot}images/versions/notification-headsup.png" />
+</div>
+
 <p>Notifications in Android 5.0 are more visible, accessible, and configurable. </p>
 
-<img src="{@docRoot}images/versions/notification-headsup.png" style="float:right; margin:0 0 40px 60px" width="300" height="224" />
 
 <p>Varying notification details may appear <strong>on the lock screen</strong> if desired by the user. Users may elect to allow none, some, or all notification content to be shown on a secure lock screen. </p>
 
@@ -119,8 +106,6 @@
 
 <p>A new media notification template provides consistent media controls for notifications with up to 6 action buttons, including custom controls such as "thumbs up"&mdash;no more need for RemoteViews!</p>
 
-
-
 <h2 id="TV">Your apps on the big screen</h2>
 
 <p><a href="http://developer.android.com/tv/index.html">Android TV</a> provides a complete TV platform for your app's big screen experience. Android TV is centered around a simplified home screen experience that allows users to discover content easily, with personalized recommendations and voice search.</p>
@@ -131,12 +116,14 @@
 
 <p>The TV Input Framework provides access to a wide variety of live TV input sources and brings them together in a single user interface for users to browse, view, and enjoy content. Building a TV input service for your content can help make your content more accessible on TV devices.</p>
 
-
-
-<img src="{@docRoot}images/versions/recents_screen_2x.png" srcset="{@docRoot}images/versions/recents_screen.png 1x, {@docRoot}images/versions/recents_screen_2x.png 2x" style="float:right; margin:0 0 40px 60px" width="300" height="521" />
-
 <h2 id="Documents">Document-centric apps</h2>
 
+<div style="float:right;margin:1em;max-width:320px">
+<img src="{@docRoot}images/versions/recents_screen_2x.png"
+    srcset="/images/versions/recents_screen.png 1x, /images/versions/recents_screen_2x.png 2x" />
+<p class="img-caption">Document-centric recents.</p>
+</div>
+
 <p>Android 5.0 introduces a redesigned Overview space (formerly called Recents) that’s more versatile and useful for multitasking.</p>
 
 <p>New APIs allow you to show separate activities in your app as individual documents alongside other recent screens.</p>
@@ -144,7 +131,6 @@
 <p>You can take advantage of concurrent documents to provide users instant access to more of your content or services. For example, you might use concurrent documents to represent files in a productivity app, player matches in a game, or chats in a messaging app. </p>
 
 
-
 <h2 id="Connectivity">Advanced connectivity</h2>
 
 <p>Android 5.0 adds new APIs that allow apps to perform concurrent operations with <strong>Bluetooth Low Energy</strong> (BLE), allowing both scanning (central mode) and advertising (peripheral mode).</p>
@@ -159,14 +145,13 @@
 
 <p>Support for <strong><a href="http://www.khronos.org/opengles/3_X/">Khronos OpenGL ES 3.1</a></strong> now provides games and other apps the highest-performance 2D and 3D graphics capabilities on supported devices. </p>
 
-<p>OpenGL ES 3.1 adds compute shaders, stencil textures, accelerated visual effects, high quality ETC2/EAC texture compression, advanced texture rendering, standardized texture size and render-buffer formats, and more.</p>
-
-
-<div class="figure" style="width:350px; margin:0 0 0 60px">
-<img src="{@docRoot}images/versions/rivalknights.png" style="float:right;" width="350" height="525" />
+<div style="float:right;margin:1em;max-width:350px">
+<img src="{@docRoot}images/versions/rivalknights.png"  />
 <p class="img-caption">Gameloft's Rival Knights uses ASTC (Adaptive Scalable Texture Compression) from AEP and Compute Shaders from ES 3.1 to deliver HDR (High Dynamic Range) Bloom effects and provide more graphical detail.</p>
 </div>
 
+<p>OpenGL ES 3.1 adds compute shaders, stencil textures, accelerated visual effects, high quality ETC2/EAC texture compression, advanced texture rendering, standardized texture size and render-buffer formats, and more.</p>
+
 <p>Android 5.0 also introduces the <strong>Android Extension Pack</strong> (AEP), a set of OpenGL ES extensions that give you access to features like tessellation shaders, geometry shaders, ASTC texture compression, per-sample interpolation and shading, and other advanced rendering capabilities. With AEP you can deliver high-performance graphics across a range of GPUs.</p>
 
 
@@ -182,7 +167,7 @@
 
 <p>Android now includes support for standard <strong>USB audio</strong> peripherals, allowing users to connect USB headsets, speakers, microphones, or other high performance digital peripherals. Android 5.0 also adds support for <strong>Opus</strong> audio codecs.</p>
 
-<p>New <strong>{@link android.media.session.MediaSession}</strong> APIs for controlling media playback now make it easier to provide consistent media controls across screens and other controllers.</p>
+<p>New <strong><code><a href="{@docRoot}reference/android/media/session/MediaSession.html">MediaSession</a></code></strong> APIs for controlling media playback now make it easier to provide consistent media controls across screens and other controllers.</p>
 
 
 <h2 id="Camera">Enhanced camera &amp; video</h2>
@@ -198,19 +183,17 @@
 <p>Android 5.0 also adds support for <strong>multimedia tunneling</strong> to provide the best experience for ultra-high definition (4K) content and the ability to play compressed audio and video data together. </p>
 
 
+<h2 id="Work">Android in the workplace</h2>
 
-<div class="figure" style="width:320px; margin:1em 0 0 20px;padding-left:2em;">
-<img style="float:right; margin:0 1em 1em 2em"
+<div style="float:right;margin:1em;max-width:330px">
+<img 
     src="{@docRoot}images/android-5.0/managed_apps_launcher@2x.png"
-    srcset="{@docRoot}images/android-5.0/managed_apps_launcher@2x.png 2x"
-    alt="" width="300" />
+    srcset="/images/android-5.0/managed_apps_launcher@2x.png 2x"
+    alt="" />
 <p class="img-caption">Users have a unified view of their personal and work apps, which are
 badged for easy identification.</p>
 </div>
 
-
-<h2 id="Work">Android in the workplace</h2>
-
 <p>To enable bring-your-own-device for enterprise environments, a new
 <a href="{@docRoot}about/versions/android-5.0.html#Enterprise">managed provisioning process</a>
 creates a secure work profile on the device. In the launcher, apps are shown with a Work badge to
@@ -226,8 +209,6 @@
 issue these devices with a device owner app already installed that
 can configure global device settings.</p>
 
-
-
 <h2 id="ScreenCapture">Screen capturing and sharing</h2>
 
 <p>Android 5.0 lets you add screen capturing and screen sharing capabilities to your app. </p>
@@ -242,14 +223,13 @@
 <p>New <strong>interaction composite sensors</strong> are now available to detect special interactions such as a <em>wake up</em> gesture, a <em>pick up</em> gesture, and a <em>glance</em> gesture.</p>
 
 
-
 <h2 id="WebView">Chromium WebView</h2>
 
 <div style="float:right;margin:1em 2em 1em 2em;">
-  <img src="/images/kk-chromium-icon.png" alt="" height="160" style="margin-bottom:0em;">
+  <img src="{@docRoot}images/kk-chromium-icon.png" alt="" height="160" style="margin-bottom:0em;">
 </div>
 
-<p>The initial release for Android 5.0 includes a version of Chromium for {@link android.webkit.WebView} based on the Chromium M37 release, adding support for <strong>WebRTC</strong>, <strong>WebAudio</strong>, and <strong>WebGL</strong>. </p>
+<p>The initial release for Android 5.0 includes a version of Chromium for <code><a href="{@docRoot}reference/android/webkit/WebView.html">WebView</a></code> based on the Chromium M37 release, adding support for <strong>WebRTC</strong>, <strong>WebAudio</strong>, and <strong>WebGL</strong>. </p>
 
 <p>Chromium M37 also includes native support for all of the <strong>Web Components</strong> specifications: Custom Elements, Shadow DOM, HTML Imports, and Templates. This means you can use <a href="http://polymer-project.org/">Polymer</a> and its <a href="https://www.polymer-project.org/docs/elements/material.html">material design elements</a> in a WebView without needing polyfills.</p>
 
@@ -257,8 +237,6 @@
 
 <p>As new versions of Chromium become available, users can update from Google Play to ensure they get the latest enhancements and bug fixes for WebView, providing the latest web APIs and bug fixes for apps using WebView on Android 5.0 and higher.</p>
 
-
-
 <h2 id="Accessibility">Accessibility &amp; input</h2>
 
 <p>New accessibility APIs can retrieve detailed information about the properties of windows on the screen that sighted users can interact with and define standard or customized input actions for UI elements.</p>
@@ -266,13 +244,12 @@
 <p>New Input method editor (IME) APIs enable faster switching to other IMEs directly from the input method.</p>
 
 
-
 <h2 id="Battery">Tools for building battery-efficient apps</h2>
 
 <p>New <strong>job scheduling</strong> APIs allow you optimize battery life by deferring jobs for the system to run at a later time or under specified conditions, such as when the device is charging or connected to Wi-Fi.</p>
 
 <p>A new <code>dumpsys batterystats</code> command generates <strong>battery usage statistics</strong> that you can use to understand system-wide power use and understand the impact of your app on the device battery. You can look at a history of power events, approximate power use per UID and system component, and more.</p>
 
-<img src="{@docRoot}images/versions/battery_historian.png" srcset="{@docRoot}images/versions/battery_historian@2x.png 2x" alt="" width="760" height="462" />
+<img src="{@docRoot}images/versions/battery_historian.png" srcset="/images/versions/battery_historian@2x.png 2x" alt="" width="760" height="462" />
 <p class="img-caption">Battery Historian is a new tool to convert the statistics from <code>dumpsys batterystats</code> into a visualization for battery-related debugging. You can find it at <a href="https://github.com/google/battery-historian"
->https://github.com/google/battery-historian</a>.</p>
+>https://github.com/google/battery-historian</a>.</p>
\ No newline at end of file
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index d66f8f4..f516677 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -13,7 +13,8 @@
   <div class="wrap">
     <div class="cols dac-hero-content">
       <div class="col-1of2 col-push-1of2 dac-hero-figure">
-        <img class="dac-hero-image" src="{@docRoot}images/develop/studio-open.png">
+        <img class="dac-hero-image" src="{@docRoot}images/develop/hero_image_studio5_2x.png"
+          srcset="/images/develop/hero_image_studio5.png 1x, /images/develop/hero_image_studio5_2x.png 2x" />
       </div>
       <div class="col-1of2 col-pull-1of2">
         <h1 class="dac-hero-title">Get Started with Android Studio</h1>
@@ -60,7 +61,7 @@
        data-maxResults="3"></div>
 </div></section>
 
-<section class="dac-section dac-section-light"><div class="wrap">
+<section class="dac-section dac-light"><div class="wrap">
   <h1 class="dac-section-title">Tools for building apps</h1>
   <div class="dac-section-subtitle">
     Insights into Android's tools and libraries to speed your development.
@@ -74,7 +75,7 @@
   </ul>
 </div></section>
 
-<section class="dac-section dac-light"><div class="wrap">
+<section class="dac-section dac-section-light"><div class="wrap">
   <h1 class="dac-section-title">Android performance patterns</h1>
   <div class="dac-section-subtitle">
     Everything you need to know about improving your app’s performance.
diff --git a/docs/html/distribute/analyze/index.jd b/docs/html/distribute/analyze/index.jd
index f948dbd..c40a699 100644
--- a/docs/html/distribute/analyze/index.jd
+++ b/docs/html/distribute/analyze/index.jd
@@ -31,8 +31,6 @@
   data in AdMob</a> and have the full picture of your app revenue.
 </p>
 
-<div class="dynamic-grid">
-
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/analyzelanding"
     data-cardSizes="6x6"
diff --git a/docs/html/distribute/analyze/start.jd b/docs/html/distribute/analyze/start.jd
index 2a5a9f4..c3a1f87 100644
--- a/docs/html/distribute/analyze/start.jd
+++ b/docs/html/distribute/analyze/start.jd
@@ -1,7 +1,7 @@
 page.title=Get Started with Analytics
 page.metaDescription=Unlock the power of Analytics by choosing the implementation that works best for your app.
 page.tags="analytics, user behavior"
-page.image=distribute/images/gp-analytics-logo.jpg
+page.image=images/cards/card-analytics_2x.png
 
 
 @jd:body
diff --git a/docs/html/distribute/engage/ads.jd b/docs/html/distribute/engage/ads.jd
index 9ca72f3..ad6940f 100644
--- a/docs/html/distribute/engage/ads.jd
+++ b/docs/html/distribute/engage/ads.jd
@@ -15,21 +15,26 @@
   app engagement campaigns</a>.
 </p>
 
-<div>
- <div class="figure-left" style="width:46%;">
+
+
+<div class="wrap">
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-1of2">
    <h3>From search</h3>
    <img src="/images/distribute/promote_ads.png">
     <p class="figure-caption">Add deep links to your app, then bring users straight
     to relevant app content when they’re searching.</p>
-  </div>
-  <div class="figure-right" style="width:46%;">
+    </div>
+    <div class="col-1of2">
     <h3>From apps</h3>
     <img src="/images/distribute/promote_ads_inapp.png">
     <p class="figure-caption">Use remarketing and deep links to bring users to just the right
     place in your app to re-engage and convert, from other apps and games they love.</p>
+    </div>
   </div>
 </div>
 
+
 <h3 id="tips">Tips</h2>
 
 <ul>
diff --git a/docs/html/distribute/engage/appindexing.jd b/docs/html/distribute/engage/appindexing.jd
deleted file mode 100644
index 2b8f315..0000000
--- a/docs/html/distribute/engage/appindexing.jd
+++ /dev/null
@@ -1,61 +0,0 @@
-page.title=Bring Users from Google Search
-page.metaDescription=Use search to bring your existing users back into your app.
-page.image=images/cards/adwords_2x.jpg
-page.tags="engagement, search"
-@jd:body
-
-<p>Use the features of Google Search for Android to drive the use of your apps: </p>
-
-<ul>
-<li>Once users have installed your app, search can bring them back with <strong>deep-links</strong> direct to your app. </li>
-  <li>When users use <strong>voice commands</strong> to ask Google to perform a task, your app can be one of those
-completing the task.</li>
-
-<li>You can also take advantage of <strong>Google Now</strong> to
-display cards for event, flight, hotel, and restaurant reservations you notify
-to users’ gmail addresses, and bring users back from the email linked to the
-card.</li>
-</ul>
-
-<p>Start now by <a href="https://developers.google.com/app-indexing/">indexing your app</a>, then take advantage of <a href="https://developers.google.com/voice-actions/">Voice Actions</a>, the <a href="https://developers.google.com/app-indexing/webmasters/appindexingapi">App Indexing API</a>, and <a href="https://developers.google.com/schemas/now/cards">Google Now Cards</a>.</p>
-
-
-<h2 id="help_users_find_your_information">Help Users Find Your Information</h2>
-
-<p>Re-engage with your users with deep-links displayed in search results, links
-that take users directly to content within your app.</p>
-
-
-<div style="margin-top:1.5em;margin-left:24px">
-<img src="{@docRoot}images/distribute/more-app-engagement.png">
-</div>
-<h2 id="empower_users_in_your_app">Empower your users to get things done in your app</h2>
-
-<p>Brings your users into your app to take action with voice actions such as “Ok
-Google, play a song” with the music app of choice, or “Ok Google, search for
-hotels in Maui on TripAdvisor” in the TripAdvisor app.</p>
-
-<div style="margin-top:1em">
-<img src="{@docRoot}images/distribute/music-action.png">
-</div>
-
-
-<h2 id="assist_your_users">Assist your users where and when they need it</h2>
-
-<div class="figure">
-<img src="https://developers.google.com/schemas/images/now_eventconfirmation.png">
-</div>
-
-<p>Inform your users of their reservations with cards created from structured data
-markup delivered in Gmail notifications. Cards also lead users quickly back to
-your email message, for further engagement.</p>
-
-<h2 style="clear:both" id="related-resources">Related Resources</h2>
-
-<div class="resource-widget resource-flow-layout col-13"
-  data-query="collection:distribute/engage/appindexing"
-  data-sortOrder="-timestamp"
-  data-cardSizes="9x3"
-  data-maxResults="6"></div>
-
-
diff --git a/docs/html/distribute/engage/deep-linking.jd b/docs/html/distribute/engage/deep-linking.jd
index 0c78a50..701cb99 100644
--- a/docs/html/distribute/engage/deep-linking.jd
+++ b/docs/html/distribute/engage/deep-linking.jd
@@ -1,4 +1,4 @@
-page.title=Drive Usage with Search
+page.title=Increase Usage with Search
 page.metaDescription=Use search to bring your existing users back into your app.
 page.image=images/cards/google-search_2x.png
 page.tags=engagement, appindexing, search
@@ -47,13 +47,12 @@
 
 <h2 id="assist_your_users">Google Now</h2>
 
-<div style="margin-top:1em">
-<img src="{@docRoot}images/distribute/google-now-engagement.png">
-</div>
-
 <p>If you’re building travel, entertainment, or restaurant apps, Google Now cards
 can re-engage your users via structured data markup delivered in email notifications.</p>
 
+<div style="margin-top:1em">
+<img src="{@docRoot}images/distribute/google-now-engagement.png">
+</div>
 
 <h2 id="tips">Tips</h2>
 
@@ -70,7 +69,7 @@
 <div class="resource-widget resource-flow-layout col-13"
   data-query="collection:distribute/engage/appindexing"
   data-sortOrder="-timestamp"
-  data-cardSizes="9x3"
-  data-maxResults="6"></div>
+  data-cardSizes="6x2"
+  data-maxResults="3"></div>
 
 
diff --git a/docs/html/distribute/engage/easy-signin.jd b/docs/html/distribute/engage/easy-signin.jd
index 2bfa5d1..924c5b4 100644
--- a/docs/html/distribute/engage/easy-signin.jd
+++ b/docs/html/distribute/engage/easy-signin.jd
@@ -1,105 +1,76 @@
-page.title=Make Signing In Easy
+page.title=Add Quick and Secure Google Sign-in
 page.metaDescription=Increase conversion rates while helping users minimize typing by letting users sign in with Google+.
-page.tags="google+"
+page.tags="google", "identity", "signin"
 page.image=images/cards/google-sign-in_2x.png
 
-
 @jd:body
 
-<div class="sidebox-wrapper" style="float:right;">
-  <div class="sidebox" style="width:360px;">
-    <p>
-      <strong>Tip:</strong> For game developers, Google+ signin is already
-      included as part of Google Play game services.
-    </p>
+<p>Get people into your apps quickly and securely, using a registration system they
+already use and trust – their Google account. With minimal effort, you can increase
+registration and sign-in conversion by adding trusted registration system that's
+familiar to users, consistent across devices, and quick and easy to use.</p>
+
+<p>Get started <a href="https://developers.google.com/identity/sign-in/">integrating
+Google sign-in into your apps and games</a>.</p>
+
+<div class="wrap">
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-3of12">
+      <h3>Quick and secure app access</h3>
+        <p>A secure authentication system that makes sign-in easy for your users by
+        letting them use their Google account, which they already use with Gmail,
+        Play, Google+, and other Google services.</p>
+    </div>
+    <div class="col-8of12 col-push-1of12">
+     <img src="{@docRoot}images/distribute/signin-secure.png" style="padding-top:1em;">
+    </div>
+  </div>
+
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-3of12">
+      <h3>Seamless experience across screens</h3>
+      <p>Keep your users engaged, no matter what device they pick up or sit down at.
+      Offer a seamless app experience across devices and into your website, securely
+      from a one-time consent. </p>
+    </div>
+    <div class="col-8of12  col-push-1of12">
+      <img src="{@docRoot}images/distribute/signin-seamless.png" style="padding-top:1em;">
+    </div>
+  </div>
+
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-3of12">
+      <h3>Help your users take action with Google</h3>
+        <p>Securely connect users with Google services and let them pay with Google
+        Wallet, share with Google contacts, save files to Drive, add events to
+        Calendar, and more.</p>
+    </div>
+    <div class="col-8of12 col-push-1of12">
+     <img src="{@docRoot}images/distribute/signin-apps.png" style="padding-top:1em;">
+    </div>
   </div>
 </div>
 
-<p>
-  Increase conversion rates while helping users minimize typing by letting
-  users sign in with Google+. The <a href=
-  "{@docRoot}google/play-services/plus.html">Google+ platform for Android</a>
-  authenticates users with their Google credentials safely and securely. With
-  your <a href="https://developers.google.com/+/mobile/android/sign-in">users
-  signing in with Google</a>, you can create more engaging experiences and
-  drive the use of your apps .
-</p>
 
-<div style="width:450px;">
-  <img src="{@docRoot}images/google/gps-googleplus.png" style="padding-top:1em;">
-</div>
-
-<p>
-  Use the Google+ social graph to welcome users by name, display their
-  pictures, connect them with friends and more. Users authenticate once and
-  then are signed-in automatically when they come back, eliminating the need to
-  remember and type names and passwords.
-</p>
-
-<div class="headerLine">
-  <h2>
-    And Spreading the Word a Snap
-  </h2>
-
-
-</div>
-
-
-<div class="figure" style="float:right;">
-  <img src="{@docRoot}images/gp-engage-share-plus.png" style=
-  "width:160px;padding-top:1em;">
-  <p class="img-caption">
-    Easy sharing through Google+
-  </p>
-</div>
-
-
-<p>
-  Using Google+ can help users spread the word about your apps to their
-  friends, attracting them to your apps, right from within your apps:
-</p>
-
-<p>
-  Google+ is also a great way to build a community of loyal fans that will help
-  you with <a href=
-  "https://support.google.com/googleplay/android-developer/answer/3131213">beta
-  testing</a>.
-</p>
+<h2>Tips</h2>
 
 <ul>
-  <li>Using a <a href=
-  "https://developers.google.com/+/mobile/android/recommend">native +1
-  button</a> to let users make a recommendation for your apps or their content.
-  </li>
-
-  <li>
-    <a href="https://developers.google.com/+/mobile/android/share/">Share rich
-    content</a> to the Google+ stream, including text, photos, URL attachments,
-    and location.
-  </li>
-
-  <li>Create <a href=
-  "https://developers.google.com/+/mobile/android/share/interactive-post">Interactive
-  posts</a> to share your website or apps, users can even invite friends to
-  "listen," "RSVP," "check-in," or one of over 100 actions.
-  </li>
+<li>Add <strong>over-the-air installs</strong> to your website. After signing in with Google
+  on the web, users will have the option to send your Android app to their device instantly,
+  without them ever leaving your website.</li>
+  <li>With Google sign-in, you can take advantage of other <strong>Google+ platform
+  features</strong> like adding a +1 button so users can make recommendations and the ability
+  to share rich content to the Google+ stream.</li>
 </ul>
 
-<p style="clear:both">
-</p>
-  <div class="headerLine">
-    <h2 id="related-resources">
-      Related Resources
-    </h2>
 
+<h2 style="clear:both" id="related-resources">Related Resources</h2>
 
-  </div>
-
-  <div class="resource-widget resource-flow-layout col-13"
+<div class="resource-widget resource-flow-layout col-13"
   data-query="collection:distribute/engage/gplus"
   data-sortorder="-timestamp"
   data-cardsizes="9x3"
-  data-maxresults="6">
-  </div>
+  data-maxresults="4">
 </div>
 
+
diff --git a/docs/html/distribute/engage/engage_toc.cs b/docs/html/distribute/engage/engage_toc.cs
index 7094713..f8607f5 100644
--- a/docs/html/distribute/engage/engage_toc.cs
+++ b/docs/html/distribute/engage/engage_toc.cs
@@ -20,7 +20,7 @@
   <li class="nav-section">
     <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs
         var:toroot?>distribute/engage/easy-signin.html">
-        <span class="en">Make Signing In Easy</span></a>
+        <span class="en">Add Google Sign-in</span></a>
     </div>
   </li>
   <li class="nav-section">
@@ -41,7 +41,6 @@
         <span class="en">Use the Power of Intents</span></a>
     </div>
   </li>
-
   <li class="nav-section">
     <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs
         var:toroot?>distribute/engage/analytics.html">
diff --git a/docs/html/distribute/engage/index.jd b/docs/html/distribute/engage/index.jd
index a47e004..165cc0e 100644
--- a/docs/html/distribute/engage/index.jd
+++ b/docs/html/distribute/engage/index.jd
@@ -11,8 +11,6 @@
   techniques to keep your users coming back.
 </p>
 
-<div class="dynamic-grid">
-
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/engagelanding"
     data-cardSizes="6x6"
@@ -20,22 +18,14 @@
   </div>
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/engagelanding"
-    data-cardSizes="6x2"
+    data-cardSizes="6x3"
     data-maxResults="20">
   </div>
 
-  <h3>Related Resources</h3>
+<!--  <h2>Related Resources</h2>
   <div class="resource-widget resource-flow-layout col-16"
-    data-query="type:youtube+tag:engagement"
-    data-sortOrder="-timestamp"
-    data-cardSizes="6x3"
+    data-query="tag:engagement"
+    data-sortOrder="random"
+    data-cardSizes="6x2"
     data-maxResults="3">
-  </div>
-  <div class="resource-widget resource-flow-layout col-16"
-    data-query="type:blog+tag:engagement"
-    data-sortdOrder="-timestamp"
-    data-cardSizes="6x3"
-    data-maxResults="3">
-  </div>
-
-</div>
\ No newline at end of file
+  </div> -->
diff --git a/docs/html/distribute/essentials/best-practices/apps.jd b/docs/html/distribute/essentials/best-practices/apps.jd
deleted file mode 100644
index bbac727..0000000
--- a/docs/html/distribute/essentials/best-practices/apps.jd
+++ /dev/null
@@ -1,260 +0,0 @@
-page.title=App Developer Best Practices
-page.image=/distribute/images/gp-app-practices.png
-page.metaDescription=Essential tips for launching successful apps in Google Play.
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Best Practices</h2>
-<ol>
-<li><a href="#essentials">Get the Essentials Right</a></li>
-<li><a href="#users">Get Users</a></li>
-<li><a href="#engage">Engage and Retain</a></li>
-<li><a href="#beyond">Beyond the Basics</a></li>
-<li><a href="#related-resources">Related Resources</a></li>
-</ol>
-</div></div>
-
-<p>The following best practices have enabled developers worldwide to build great, successful apps for Google Play.</p>
-
-<div class="headerLine">
-<h2 id="essentials">Get the Essentials Right</h2>
-</div>
-
-<h3>1. Make it Android</h3>
-
-<ul>
-  <li>
-  <p>
-    Build your apps to make best use of the unique Android features, such as
-    <a href="{@docRoot}distribute/engage/widgets.html">widgets</a>, <a href=
-    "{@docRoot}distribute/engage/notifications.html">rich notifications</a>,
-    <a href=
-    "http://android-developers.blogspot.com/2012/02/share-with-intents.html">sharing
-    through Intents</a>, and more.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Add the power of Google features your users already love, such as
-    <a href="https://developers.google.com/maps/documentation/android/">Google
-    Maps</a>, <a href="https://developers.google.com/drive/">Google
-    Drive</a>, and more, all with <a href=
-    "https://developers.google.com/+/mobile/android/sign-in">single sign
-    on</a>.
-  </p>
-  </li>
-</ul>
-
-<h3>
-  2. Make it quality
-</h3>
-
-<ul>
-  <li>
-  <p>
-    Make sure your apps follow the <a href=
-    "{@docRoot}distribute/essentials/quality/core.html">Core App Quality</a>
-    guidelines.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Create apps that are available on all form factors and screen sizes, by
-    following the <a href=
-    "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App
-    Quality</a> guidelines.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Test and <a href=
-    "{@docRoot}distribute/essentials/optimizing-your-app.html">optimize your
-    quality</a> at every step and make use of the Google Play <a href=
-    "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing</a>
-    and <a href=
-    "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
-    rollouts</a> features to test with users before launch.
-  </p>
-  </li>
-</ul>
-
-<div class="headerLine">
-  <h2 id="users">
-  Get Users
-  </h2>
-
-
-</div>
-
-<h3>
-  1. Build buzz
-</h3>
-
-<ul>
-  <li>
-  <p>
-    Create a great <a href="{@docRoot}distribute/users/your-listing.html">app
-    listing page</a> to showcase your apps and grab users’ attention. Don’t
-    forget to include a <a href=
-    "{@docRoot}distribute/engage/video.html">YouTube video</a>.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    <a href="{@docRoot}distribute/tools/launch-checklist.html">Launch</a> on
-    multiple platforms simultaneously to maximize your reach.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Promote your apps with the official <a href=
-    "{@docRoot}distribute/tools/promote/badges.html">Google Play badge</a>
-    and <a href="{@docRoot}distribute/tools/promote/linking.html">link to
-    your products</a> on Google Play.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Build a community with social media, <a href=
-    "http://groups.google.com/">forums</a>, and <a href=
-    "http://plus.google.com">communities</a> to get and keep users talking.
-  </p>
-  </li>
-</ul>
-
-<h3>
-  2. Optimize for great ratings
-</h3>
-
-<ul>
-  <li>
-  <p>
-    Get to <a href="{@docRoot}distribute/users/know-your-user.html">know your
-    users</a>, listen to and <a href=
-    "{@docRoot}distribute/engage/app-updates.html">update your apps</a> from
-    their feedback.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Focus on your strength markets first, get these right before expanding.
-  </p>
-  </li>
-</ul>
-
-<div class="headerLine">
-  <h2 id="engage">
-  Engage and Retain
-  </h2>
-
-
-</div>
-
-<h3>
-  1. Keep users coming back
-</h3>
-
-<ul>
-  <li>
-  <p>
-    Use <a href="{@docRoot}google/play/billing/index.html">Google Play In-app
-    Billing</a> to offer subscriptions to extended features.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Hold competitions and offer promotions, then announce them through
-    <a href="{@docRoot}design/patterns/notifications.html">notifications</a>.
-  </p>
-  </li>
-</ul>
-
-<h3>
-  2. Earn users’ love
-</h3>
-
-<ul>
-  <li>
-  <p>
-    <a href=
-    "http://android-developers.blogspot.com/2013/05/all-google-play-developers-can-now.html">
-    Respond to reviews</a> and get valuable feedback from the community
-    you've built.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    <a href=
-    "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
-    Measure</a> your campaigns to see what is driving users to install your
-    apps.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    <a href=
-    "{@docRoot}distribute/essentials/optimizing-your-app.html#measuring-analyzing-responding">
-    Analyze in-app use</a> to steer content updates and prolong the life of
-    your apps.
-  </p>
-  </li>
-</ul>
-
-<div class="headerLine">
-  <h2 id="beyond">
-  Beyond the Basics
-  </h2>
-
-
-</div>
-
-<ul>
-  <li>
-  <p>
-    After you’ve launched in your market of strength, <a href=
-    "{@docRoot}distribute/users/expand-to-new-markets.html">expand into other
-    markets</a> strategically and <a href=
-    "{@docRoot}distribute/tools/localization-checklist.html">localize</a>
-    your apps as you go.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Keep users engaged, and stay ahead of the competition, by continually
-    <a href=
-    "{@docRoot}distribute/essentials/optimizing-your-app.html">optimizing
-    your apps</a> to offer new and better features, or retire those that
-    users aren’t using.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Build educational apps: learn <a href=
-    "{@docRoot}distribute/googleplay/edu/start.html">how to make apps for
-    Google Play for Education</a>.
-  </p>
-  </li>
-</ul>
-
-<div class="headerLine">
-<h2 id="related-resources">Related Resources</h2>
-</div>
-
-<div class="resource-widget resource-flow-layout col-13"
-  data-query="collection:distribute/toolsreference/bestpractices/apps"
-  data-sortOrder="-timestamp"
-  data-cardSizes="9x3,9x3"
-  data-maxResults="6"></div>
-
diff --git a/docs/html/distribute/essentials/best-practices/games.jd b/docs/html/distribute/essentials/best-practices/games.jd
deleted file mode 100644
index c4ce66e..0000000
--- a/docs/html/distribute/essentials/best-practices/games.jd
+++ /dev/null
@@ -1,259 +0,0 @@
-page.title=Game Developer Best Practices
-page.image=/distribute/images/gp-games-practices.png
-page.metaDescription=Essential tips for launching successful games in Google Play.
-
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Best Practices</h2>
-<ol>
-<li><a href="#users">Get Users</a></li>
-<li><a href="#engage">Engage and Retain</a></li>
-<li><a href="#beyond">Beyond the Basics</a></li>
-<li><a href="#related-resources">Related Resources</a></li>
-</ol>
-</div></div>
-
-<p>
-  The following best practices have enabled developers worldwide to build
-  great, successful games for Google Play.
-</p>
-
-<div class="headerLine">
-  <h2 id="users">
-  Get Users
-  </h2>
-
-
-</div>
-
-<h3>
-  1. Optimize for great ratings
-</h3>
-
-<ul>
-  <li>
-  <p>
-    <a href=
-    "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">Beta
-    test</a> to ensure your games are ready and poised for great ratings.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Optimize graphics, frame rates, and responsiveness with the <a href=
-    "http://android-developers.blogspot.com/2013/09/using-hardware-scaler-for-performance.html">
-    Hardware Scaler</a> and <a href=
-    "{@docRoot}training/graphics/opengl/index.html">OpenGL ES</a>.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Be sure your APK is small, then provide game content through over-the-air
-    downloads.
-  </p>
-  </li>
-</ul>
-
-<h3>
-  2. Build buzz
-</h3>
-
-<ul>
-  <li>
-  <p>
-    Build a community with social media, <a href=
-    "{@docRoot}distribute/users/build-community.html">communities</a> to get
-    and keep users talking.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Promote your games with official <a href=
-    "{@docRoot}distribute/tools/promote/badges.html">Google Play badges</a>
-    and <a href="{@docRoot}distribute/tools/promote/linking.html">links to
-    your products</a> on Google Play.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    If you ship on multiple platforms, doing so at the same time can maximize
-    your marketing impact.
-  </p>
-  </li>
-</ul>
-
-<h3>
-  3. Get Visibility
-</h3>
-
-<ul>
-  <li>
-  <p>
-    First impressions count: <a href=
-    "{@docRoot}distribute/users/your-listing.html">highlight</a> the game's
-    best features in screenshots, videos, and description.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Integrate Google Play Game Services, so your game is displayed in the
-    <a href=
-    "https://play.google.com/store/apps/details?id=com.google.android.play.games">
-    Google Play Games App</a>.
-  </p>
-  </li>
-</ul>
-
-<div class="headerLine">
-  <h2 id="engage">
-  Engage and Retain
-  </h2>
-
-
-</div>
-
-<h3>
-  1. Keep users coming back
-</h3>
-
-<ul>
-  <li>
-  <p>
-    <a href=
-    "https://developers.google.com/games/services/common/concepts/achievements">
-    Achievements</a>, <a href=
-    "https://developers.google.com/games/services/common/concepts/leaderboards">
-    leaderboards</a>, <a href=
-    "https://developers.google.com/games/services/common/concepts/realtimeMultiplayer">
-    multiplayer</a>, and <a href=
-    "https://developers.google.com/games/services/common/concepts/cloudsave">cloud
-    save</a> help engage users and bring them back.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Hold tournaments and offer promotions, then announce them through
-    <a href="{@docRoot}design/patterns/notifications.html">notifications</a>.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Sign in users early, then automatically. Before their first sign-in, save
-    progress locally.
-  </p>
-  </li>
-</ul>
-
-<h3>
-  2. Give users a reason to invest their money
-</h3>
-
-<ul>
-  <li>
-  <p>
-    A majority of the top grossing games use in-app purchases. Use them to
-    unlock content and allow players to enhance their game play.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    <a href="{@docRoot}google/play/billing/index.html">Google Play In-app
-    Billing</a> makes purchasing easy with several forms of payment.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Provide content updates regularly to give users limited edition items to
-    win or purchase.
-  </p>
-  </li>
-</ul>
-
-<h3>
-  3. Earn players’ love
-</h3>
-
-<ul>
-  <li>
-  <p>
-    <a href=
-    "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
-    Measure</a> your campaigns to see what’s driving quality users to install
-    your games.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    <a href=
-    "{@docRoot}distribute/essentials/optimizing-your-app.html#measuring-analyzing-responding">
-    Analyze in-game use</a> to steer content updates and prolong the life of your
-    games.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    <a href=
-    "http://android-developers.blogspot.com/2013/05/all-google-play-developers-can-now.html">
-    Respond to reviews</a> and get valuable feedback from the community
-    you’ve built.
-  </p>
-  </li>
-</ul>
-
-<div class="headerLine">
-  <h2 id="beyond">
-  Beyond the Basics
-  </h2>
-
-
-</div>
-
-<ul>
-  <li>
-  <p>
-    After you've launched in your market of strength, <a href=
-    "{@docRoot}distribute/users/expand-to-new-markets.html">expand into other
-    markets</a> strategically and <a href=
-    "{@docRoot}distribute/tools/localization-checklist.html">localize</a>
-    your apps as you go.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Provide content <a href=
-    "{@docRoot}distribute/engage/app-updates.html">updates on a regular
-    basis</a> to keep users engaged.
-  </p>
-  </li>
-
-  <li>
-  <p>
-    Building educational games? See the <a href=
-    "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
-    Guidelines</a>.
-  </p>
-  </li>
-</ul>
-
-<div class="headerLine">
-<h2 id="related-resources">Related Resources</h2>
-</div>
-
-<div class="resource-widget resource-flow-layout col-13"
-  data-query="collection:distribute/toolsreference/bestpractices/games"
-  data-sortOrder="-timestamp"
-  data-cardSizes="9x3,9x3"
-  data-maxResults="6"></div>
diff --git a/docs/html/distribute/essentials/essentials_toc.cs b/docs/html/distribute/essentials/essentials_toc.cs
index fe3fc87..baca18f 100644
--- a/docs/html/distribute/essentials/essentials_toc.cs
+++ b/docs/html/distribute/essentials/essentials_toc.cs
@@ -34,18 +34,7 @@
         </a>
     </div>
   </li>
-  <li class="nav-section">
-    <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/best-practices/apps.html">
-          <span class="en">App Best Practices</span>
-        </a>
-    </div>
-  </li>
-  <li class="nav-section">
-    <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/best-practices/games.html">
-          <span class="en">Game Best Practices</span>
-        </a>
-    </div>
-  </li>
+</ul>
 
 
 <script type="text/javascript">
diff --git a/docs/html/distribute/essentials/index.jd b/docs/html/distribute/essentials/index.jd
index ca5442a..d5c3397 100644
--- a/docs/html/distribute/essentials/index.jd
+++ b/docs/html/distribute/essentials/index.jd
@@ -12,23 +12,17 @@
   process of monitoring feedback and making improvement after launch.
 </p>
 
-<div class="dynamic-grid">
 <div class="resource-widget resource-flow-layout landing col-16"
   data-query="collection:distribute/essentials"
   data-cardSizes="6x6"
   data-maxResults="6">
 </div>
 
-<h3>Related resources</h3>
+<!-- <h2>Related resources</h2>
 
 <div class="resource-widget resource-flow-layout col-16"
-  data-query="type:blog+tag:quality"
-  data-cardSizes="6x3"
-  data-maxResults="3">
-</div>
-<div class="resource-widget resource-flow-layout col-16"
-  data-query="type:youtube+tag:appquality"
-  data-cardSizes="6x3"
-  data-maxResults="3">
-</div>
-</div>
\ No newline at end of file
+  data-query="tag:quality"
+  data-cardSizes="6x2"
+  data-maxResults="3"
+  data-sortOrder="random">
+</div> -->
diff --git a/docs/html/distribute/googleplay/auto.jd b/docs/html/distribute/googleplay/auto.jd
index af24a54..1f5915b 100644
--- a/docs/html/distribute/googleplay/auto.jd
+++ b/docs/html/distribute/googleplay/auto.jd
@@ -1,4 +1,4 @@
-page.title=Distributing to Android Auto
+page.title=Distribute to Android Auto
 page.image=/design/auto/images/auto-overview.png
 meta.tags="auto", "publish", "quality"
 page.tags="auto", "publish", "googleplay"
diff --git a/docs/html/distribute/googleplay/cardboard.jd b/docs/html/distribute/googleplay/cardboard.jd
index c187ffd..d5965d1 100644
--- a/docs/html/distribute/googleplay/cardboard.jd
+++ b/docs/html/distribute/googleplay/cardboard.jd
@@ -1,12 +1,11 @@
 page.title=Build VR with Google Cardboard
 page.metaDescription=Build apps and games with VR, for a viewer anyone can buy.
-page.image=images/cards/card-cardboard_2x.jpg
 page.tags=vr, carboard, games
 @jd:body
 
 <p>
   Virtual reality promises to transform the way players view games, taking them from a
-  flat world into the realm of 3D. And it’s not just games, any application that provides
+  flat world into the realm of 3D. In fact, any application that provides
   a way to visually explore has the possibility to offer users more immersive experiences
   with VR &mdash; like a virtual tour of a famous landmark or a way to visualise atoms in a
   chemical compound.
diff --git a/docs/html/distribute/googleplay/cast.jd b/docs/html/distribute/googleplay/cast.jd
index 68c0584..55bc1a9 100644
--- a/docs/html/distribute/googleplay/cast.jd
+++ b/docs/html/distribute/googleplay/cast.jd
@@ -1,13 +1,12 @@
-page.title=Stream Your Content with Google Cast
-page.metaDescription=Let users stream your video and audio content to TVs and speakers.
-page.image=images/cards/card-cast_2x.jpg
+page.title=Stream with Google Cast
+page.metaDescription=Let users stream your video and audio content to their TVs and speakers.
 page.tags=cast, video, chromecast
 @jd:body
 
 <p>
-  The average person spends 3 hours per day watching the TV. With Google Cast
+  With Google Cast
   you make it easy for users to include your content as part of their viewing
-  schedule. All they need is an Android TV, a TV with a Chromecast plugged in,
+  on TV and listening on audio systems. All they need is an Android TV, a TV with a Chromecast plugged in,
   or a Cast for audio device connected to their audio system.
 </p>
 
diff --git a/docs/html/distribute/googleplay/edu/about.jd b/docs/html/distribute/googleplay/edu/about.jd
index 469b899..36a67b26 100644
--- a/docs/html/distribute/googleplay/edu/about.jd
+++ b/docs/html/distribute/googleplay/edu/about.jd
@@ -33,18 +33,20 @@
       <img src="{@docRoot}images/gpfe-developer.png">
     </div>
 
-    <h3>
-      FOR DEVELOPERS
-    </h3>
-    <b>Get discovered</b>
-    <p>
-      With Google Play for Education, teachers and administrators can browse
+
+
+<div class="wrap">
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-6of12">
+      <h2 id="maximize_your_ad_revenue">For developers</h2>
+      <img src="{@docRoot}images/gpfe-developer.png">
+      <h5>Get discovered</h5>
+      <p>With Google Play for Education, teachers and administrators can browse
       content by curriculum, grade, and standard &mdash; discovering the right
       content for their students. If your app offers an exciting new way to
       learn sixth grade algebra, math educators will be able to find, purchase,
-      and distribute your app to their classes in a few clicks.
-    </p>
-    <b>Reach more schools and students</b>
+      and distribute your app to their classes in a few clicks.</p>
+      <h5>Reach more schools and students</h5>
     <p>
       Millions of students, faculty, and staff are using Google Apps for
       Education and other Google services. Many of these schools are excited to
@@ -52,55 +54,52 @@
       looking to bring your apps into their classrooms, especially apps using
       Google sign-on.
     </p>
-    <b>Monetize effectively</b>
+      <h5>Monetize effectively</h5>
     <p>
       With Google Play for Education, educators are able to make high-volume
       purchases using standard institutional payment mechanisms and then
       distribute apps to the students who need them — whether it’s a class of
       20 or a district of 20,000.
     </p>
-  </div>
-
-  <div style="width:48%; margin-left:2%; float:left;">
-    <div class="centered-full-image">
-      <img src="{@docRoot}images/gpfe-educator.png">
     </div>
 
-    <h3>
-      FOR EDUCATORS
-    </h3>
-    <b>Android tablets in the classroom</b>
+
+    <div class="col-6of12">
+      <h2 id="maximize_your_ad_revenue">For educators</h2>
+      <img src="{@docRoot}images/gpfe-educator.png">
+      <h5>    <b>Android tablets in the classroom</h5>
     <p>
       Google Play for Education brings the innovation of Android technology
       into classrooms. School districts can set up and deploy large numbers of
       devices in just minutes or hours, rather than days.
     </p>
-    <b>Curriculum-based discovery</b>
+      <h5>Curriculum-based discovery</h5>
     <p>
       Powerful browsing tools let educators quickly discover apps, videos, and
       other content—with many recommended by teachers and categorized according
       to familiar Core Curriculum standards.
     </p>
-    <b>Bulk purchase with institutional payment</b>
+      <h5>Bulk purchase with institutional payment</h5>
     <p>
       Convenient purchasing and delivery tools let educators buy apps in bulk,
       using purchase orders and other payment methods that are easy for schools
       to manage.
     </p>
-    <b>Over-the-air delivery to student devices</b>
+      <h5>Over-the-air delivery to student devices</h5>
     <p>
       After finding apps they want, educators can push them instantly to
       student devices over the air. They can send the apps to individuals or
       groups of any size, across classrooms, schools, or even districts.
     </p>
+      <h5>Business-wide licensing</h5>
+      <p>Paid apps are licensed to your organization, enabling you to move paid apps between users as users needs change and staff turns over. </p>
+    </div>
   </div>
 </div>
 
-<p style="clear:both">
-</p>
-<div class="headerLine">
+
 <h2 id="related-resources">Related Resources</h2>
-</div>
+
 
 <div class="dynamic-grid">
 
diff --git a/docs/html/distribute/googleplay/families/faq.jd b/docs/html/distribute/googleplay/families/faq.jd
index 9f916a8..363dc91 100644
--- a/docs/html/distribute/googleplay/families/faq.jd
+++ b/docs/html/distribute/googleplay/families/faq.jd
@@ -1,4 +1,4 @@
-page.title=Frequently Asked Questions
+page.title=Google Play for Families FAQ
 meta.tags="families", "guidelines", "quality"
 page.tags="families", "addendum"
 page.metaDescription=Questions and answers about Designed for Families
diff --git a/docs/html/distribute/googleplay/googleplay_toc.cs b/docs/html/distribute/googleplay/googleplay_toc.cs
index 8a321bb..e348ee2 100644
--- a/docs/html/distribute/googleplay/googleplay_toc.cs
+++ b/docs/html/distribute/googleplay/googleplay_toc.cs
@@ -7,7 +7,7 @@
   </li>
   <li class="nav-section">
     <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/start.html">
-            <span class="en">Get Started with Publishing</span>
+            <span class="en">Get Started <br />with Publishing</span>
           </a>
     </div>
   </li>
@@ -19,37 +19,37 @@
   </li>
   <li class="nav-section">
     <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/guide.html">
-    <span class="en">Finding Success on <span style="white-space:nowrap">Google Play</span></span>
+    <span class="en">Find Success on <span style="white-space:nowrap">Google Play</span></span>
         </a>
     </div>
   </li>
   <li class="nav-section">
     <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/wear.html">
-          <span class="en">Distributing to <span style="white-space:nowrap">Android Wear</span></span>
+    <span class="en">Distribute to <br /><span style="white-space:nowrap">Android Wear</span></span>
         </a>
     </div>
   </li>
   <li class="nav-section">
     <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/tv.html">
-          <span class="en">Distributing to <span style="white-space:nowrap">Android TV</span></span>
+          <span class="en">Distribute to <br /><span style="white-space:nowrap">Android TV</span></span>
         </a>
     </div>
   </li>
   <li class="nav-section">
     <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/auto.html">
-          <span class="en">Distributing to <span style="white-space:nowrap">Android Auto</span></span>
+          <span class="en">Distribute to <br /><span style="white-space:nowrap">Android Auto</span></span>
         </a>
     </div>
   </li>
   <li class="nav-section">
     <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/cast.html">
-          <span class="en">Stream Your Content<span style="white-space:nowrap">with Cast</span></span>
+          <span class="en">Stream Your Content <span style="white-space:nowrap">with Cast</span></span>
         </a>
     </div>
   </li>
   <li class="nav-section">
     <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/cardboard.html">
-          <span class="en"><span style="white-space:nowrap">Build VR with Cardboard</span></span>
+          <span class="en"><span style="white-space:nowrap">Build VR with Google Cardboard</span></span>
         </a>
     </div>
   </li>
@@ -84,6 +84,12 @@
         </a></li>
     </ul>
   </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/work/about.html">
+          <span class="en"><span style="white-space:nowrap">Google Play for Work</span></span>
+        </a>
+    </div>
+  </li>
 </ul>
 <script type="text/javascript">
 <!--
diff --git a/docs/html/distribute/googleplay/index.jd b/docs/html/distribute/googleplay/index.jd
index 72e2de8..1908e01 100644
--- a/docs/html/distribute/googleplay/index.jd
+++ b/docs/html/distribute/googleplay/index.jd
@@ -11,9 +11,7 @@
   help you gain traction in the marketplace.</span>
 </p>
 
-<div class="dynamic-grid">
-
-  <h3>Overview</h3>
+  <h2>Overview</h2>
 
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/gp/gplanding"
@@ -22,25 +20,20 @@
     data-maxResults="3">
   </div>
 
-  <h3>Distribute Your Apps</h3>
+  <h2>Distribute Your Apps</h2>
 
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/gp/gpfelanding"
     data-cardSizes="6x6"
-    data-maxResults="5">
+    data-maxResults="10">
   </div>
 
-  <h3>Related resources</h3>
+<!--  <h2>Related resources</h2>
 
   <div class="resource-widget resource-flow-layout col-16"
-    data-query="type:youtube+tag:growth"
-    data-cardSizes="6x3"
-    data-maxResults="3">
-  </div>
-  <div class="resource-widget resource-flow-layout col-16"
-    data-query="type:blog+tag:googleplay"
-    data-cardSizes="6x3"
-    data-maxResults="3">
-  </div>
+    data-query="tag:growth"
+    data-cardSizes="6x2"
+    data-maxResults="3"
+    data-sortOrder="random">
+  </div> -->
 
-</div>
diff --git a/docs/html/distribute/googleplay/tv.jd b/docs/html/distribute/googleplay/tv.jd
index 37cbe26..a35edbc 100644
--- a/docs/html/distribute/googleplay/tv.jd
+++ b/docs/html/distribute/googleplay/tv.jd
@@ -1,4 +1,4 @@
-page.title=Distributing to Android TV
+page.title=Distribute to Android TV
 page.image=/design/tv/images/atv-home.jpg
 meta.tags="tv", "publish", "quality"
 page.tags="tv", "publish", "googleplay"
diff --git a/docs/html/distribute/googleplay/wear.jd b/docs/html/distribute/googleplay/wear.jd
index c0a0017..7661016 100644
--- a/docs/html/distribute/googleplay/wear.jd
+++ b/docs/html/distribute/googleplay/wear.jd
@@ -1,4 +1,4 @@
-page.title=Distributing to Android Wear
+page.title=Distribute to Android Wear
 page.image=/design/media/wear/ContextualExample.008_2x.png
 meta.tags="wear", "publish", "quality"
 page.tags="wear", "publish", "googleplay"
diff --git a/docs/html/distribute/googleplay/work/about.jd b/docs/html/distribute/googleplay/work/about.jd
new file mode 100644
index 0000000..6ced561
--- /dev/null
+++ b/docs/html/distribute/googleplay/work/about.jd
@@ -0,0 +1,95 @@
+page.title=Google Play for Work
+page.metaDescription=Distribute your apps directly to enterprises and business users.
+page.tags="enterprise", "emm", "business", "administrator"
+page.image=images/distribute/android-work.jpg
+@jd:body
+
+<p>Google Play for Work is an extension of Google Play that lets Android for Work users browse and install apps. IT admins in a business using Android for Work choose which public and private apps are made available to users in their business. Businesses can use Google Play for Work to securely bulk deploy free apps to their employees or bulk purchase paid apps depending on their needs.</p>
+
+<p>As a Google Play developer, your free apps are automatically ready to be selected by Android for Work customers and made available to their workforces on Google Play for Work. However, to allow businesses access to bulk purchase your paid apps, you must opt-in and agree to the <a href="https://play.google.com/about/work/developer-distribution-agreement-addendum.html">Google Play for Work Addendum</a> to the Developer Distribution Agreement.</p>
+
+<p>Find out more about <a href="">distributing to Google Play for Work</a>.</p>
+
+<div class="wrap">
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-6of12">
+      <h2 id="maximize_your_ad_revenue">For developers</h2>
+      <img src="{@docRoot}images/distribute/gpfw_developer.png">
+      <h5>Get discovered</h5>
+      <p>Get your business related apps listed in a business specific gateway so they stand out from consumer apps.</p>
+      <h5>Get volume</h5>
+      <p>Reach new audiences at scale because businesses will be able to deploy your free apps in bulk. Bulk purchasing also allows businesses to buy your paid app at scale.</p>
+      <h5>Generate revenue from extended support</h5>
+      <p>Businesses will often look for extended support for business critical apps, and you have the opportunity to offer that support for a fee.</p>
+      <h5>Continue to offer in app-purchases</h5>
+      <p>You can continue to offer free apps with in-app purchases. Business employees will be able to make purchases just as they would if they personally installed your app. </p>
+    </div>
+
+
+    <div class="col-6of12">
+      <h2 id="maximize_your_ad_revenue">For businesses</h2>
+      <img src="{@docRoot}images/distribute/gpfw_business.png">
+      <h5>Free to businesses</h5>
+      <p>Google Play for Work is available free of charge to Android for Work customers.</p>
+      <h5>Full IT approval for apps</h5>
+      <p>IT can now approve and manage every app deployed to its organization’s workers.</p>
+      <h5>Secure app distribution</h5>
+      <p>Provides a secure gateway for distributing apps within your company, whether they are available publicly or distributed privately to employees at your organization.</p>
+      <h5>Work app configuration</h5>
+      <p>Maintain app settings, such as server addresses and default user settings, from your admin console for enabled apps.</p>
+      <h5>Business-wide licensing</h5>
+      <p>Paid apps are licensed to your organization, enabling you to move paid apps between users as users needs change and staff turns over. </p>
+    </div>
+  </div>
+</div>
+
+<h2 id="best_practices">Best practices for success</h2>
+
+<p>Keep these best practices in mind as you build a great enterprise-ready app.</p>
+
+<h3 id="design">Build a great app for business</h3>
+
+<ul>
+  <li>Follow best practices for security and manage user data properly. Businesses
+  are more conscious of data security and employee productivity, especially when it
+  comes to features that share information with other services.</li>
+  <li>Support the Work App Configuration framework to let an administrator remotely configure app settings such as:
+    <ul>
+      <li>Server address and protocol settings</li>
+      <li>The ability to switch features on and off</li>
+      <li>Sign-in credentials for your app's backend servers</li>
+      <li>Default user settings</li>
+    </ul>
+  </li>
+  <li>Request the minimum permissions that your app needs.</li>
+  <li>Make sure communication to your backend and data in your backend is secure.</li>
+  <li>Implement authorization policies that will minimize the number of your employees that can access user data.</li>
+  <li><a href={@docRoot}training/enterprise/app-compatibility.html">Offer compatibility with managed profile</a> and test that with the <a href="{@docRoot}samples/BasicManagedProfile/index.html">BasicManagedProfile sample app</a>.</li>
+  <li>Support <a href="{@docRoot}training/enterprise/app-restrictions.html">app restrictions</a> so that IT admins can remotely configure your app through leading EMM solutions.</li>
+</ul>
+
+<!--<h3 id="distribute">Distribute</h3>
+
+<p>Free to install apps are automatically made available through Google Play for Work, but for paid apps:</p>
+
+<ul>
+<li>When you <a href="https://support.google.com/googleplay/android-developer/answer/113469">publish your app through the Developer Console</a>, opt in to distribute through Google Play for Work, so you agree to your app’s licenses being transferrable within a single business customer.</li>
+<li>Use the <a href="{@docRoot}}google/play/licensing/index.html">Licensing API to track which users have licenses assigned.</li>
+</ul> -->
+
+
+<h3 id="support">Provide support and maintenance</h3>
+
+<ul>
+<li>Consider offering enhanced support to cover extended hours or specific means of contact. Businesses are often willing to pay for this service.</li>
+<li>If you update the App Configuration / App Restrictions schema for your app, make sure it remains backward compatible. This is because it’s possible that different users will have different versions of your app (at least temporarily), and IT admin will want a consistent remote configuration experience between versions to ensure efficient management of apps in the field.</li>
+</ul>
+
+<h2 id=related_resources>Related resources</h2>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/googleplay/gpfw"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
index ce64445..d3f3836 100644
--- a/docs/html/distribute/index.jd
+++ b/docs/html/distribute/index.jd
@@ -22,7 +22,7 @@
       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="6"></div>
+      data-maxResults="3"></div>
 </div></section>
 
 <section class="dac-section dac-invert dac-darken-bg" style="background-image: url(/images/distribute/google-play-bg.jpg)"><div class="wrap">
@@ -64,7 +64,11 @@
     </a></li>
     <li class="dac-section-link"><a href="/distribute/monetize/index.html">
       <span class="dac-sprite dac-auto-chevron"></span>
-      Monetize
+      Earn
+    </a></li>
+    <li class="dac-section-link"><a href="/distribute/analyze/index.html">
+      <span class="dac-sprite dac-auto-chevron"></span>
+      Analyze
     </a></li>
   </ul>
 </div></section>
@@ -77,10 +81,10 @@
   <div class="resource-widget resource-flow-layout col-16"
        data-query="collection:distribute/landing/more"
        data-cardSizes="6x6"></div>
-  <ul class="dac-section-links">
+<!--  <ul class="dac-section-links">
     <li class="dac-section-link"><a href="https://developers.google.com/">
       <span class="dac-sprite dac-auto-chevron"></span>
       More Google services for Android
     </a></li>
-  </ul>
+  </ul> -->
 </div></section>
diff --git a/docs/html/distribute/monetize/ads.jd b/docs/html/distribute/monetize/ads.jd
index 8f6c8b0..c15f2bb 100644
--- a/docs/html/distribute/monetize/ads.jd
+++ b/docs/html/distribute/monetize/ads.jd
@@ -25,89 +25,88 @@
 </ul>
 
 <p><a href="http://www.google.com/ads/admob/#subid=us-en-et-dac">Sign-up for AdMob</a>
-today and start showing ads by integrating the <a
-href="https://developers.google.com/mobile-ads-sdk/download">Google Mobile Ads SDK</a>
+today and start using the <a
+href="https://developer.android.com/google/play-services/ads.html">Google Mobile Ads SDK</a>
 in your app with a few lines of code.</p>
 
-<h2 id="key_features">Key features</h2>
+<h2 id="maximize_your_ad_revenue">Maximize your ad revenue</h2>
 
-<div style="display:inline-block">
-<h3 id="maximize_your_ad_revenue">Maximize your ad revenue</h3>
-
-<div class="col-4">
-  <h4 id="maximize_earnings">Maximize earnings</h4>
-  <p>Earn more with our industry-leading ad service, which includes <a href=
-  "https://support.google.com/admob/answer/3063564">free mediation</a> to
-  automatically improve your earnings, and access to all of Google’s advertiser
-  demand from AdMob, AdWords, and the DoubleClick Ad Exchange.</p>
+<div class="wrap">
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-4of12">
+      <h5 id="maximize_earnings">Maximize earnings</h5>
+      <p>Earn more with our industry-leading ad service, which includes <a href=
+      "https://support.google.com/admob/answer/3063564">free mediation</a> to
+      automatically improve your earnings, and access to all of Google’s advertiser
+      demand from AdMob, AdWords, and the DoubleClick Ad Exchange.</p>
+    </div>
+    <div class="col-4of12">
+      <h5 id="get_paid_fast">Get paid fast</h5>
+      <p>Get paid in local currencies quickly and reliably, with no wire fees charged by
+      AdMob.</p>
+    </div>
+    <div class="col-4of12">
+      <h5 id="easy_and_free">Easy and free</h5>
+      <p>The SDK can be installed quickly, and there are no standard fees for using the
+      platform.</p>
+    </div>
+  </div>
 </div>
 
-<div class="col-4">
-  <h4 id="get_paid_fast">Get paid fast</h4>
-  <p>Get paid in local currencies quickly and reliably, with no wire fees charged by
-  AdMob.</p>
+<h2 id="grow_your_business_with_a_trusted_partner">Grow your business with a trusted partner</h2>
+<div class="wrap">
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-6of12">
+      <h5 id="powered_by_googles_ad_technology">Powered by Google’s ad technology</h5>
+      <p>For over a decade, Google has helped millions of developers grow their digital
+      businesses.</p>
+    </div>
+    <div class="col-6of12">
+      <h5 id="auto_updates_on_google_play">Auto updates on Google Play</h5>
+      <p>AdMob’s integration with Google Play services pushes automatic performance
+        improvements to Android apps without additional SDK changes.</p>
+    </div>
+  </div>
 </div>
 
-<div class="col-4">
-  <h4 id="easy_and_free">Easy and free</h4>
-  <p>The SDK can be installed quickly, and there are no standard fees for using the
-  platform.</p>
-</div>
-</div>
 
-<div style="display:inline-block">
-<h3 id="grow_your_business_with_a_trusted_partner">Grow your business with a trusted partner</h3>
-
-<div class="col-6">
-  <h4 id="powered_by_googles_ad_technology">Powered by Google’s ad technology</h4>
-  <p>For over a decade, Google has helped millions of developers grow their digital
-  businesses.</p>
-</div>
-
-<div class="col-6">
-<h4 id="auto_updates_on_google_play">Auto updates on Google Play</h4>
-<p>AdMob’s integration with Google Play services pushes automatic performance
-  improvements to Android apps without additional SDK changes.</p>
-</div>
-</div>
-
-<div style="display:inline-block">
-<h3 id="drive_more_in-app_purchases_and_downloads">Drive more in-app purchases and downloads</h3>
-
-<div class="col-6">
-<h4 id="sell_more_in-app_purchases">Sell more in-app purchases</h4>
+<h2 id="drive_more_in-app_purchases_and_downloads">Drive more in-app purchases and downloads</h2>
+<div class="wrap">
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-6of12">
+<h5 id="sell_more_in-app_purchases">Sell more in-app purchases</h5>
 <p>Earn more revenue by intelligently promoting your in-app purchases to the users
 most likely to buy them.</p>
-</div>
-
-<div class="col-6">
-<h4 id="promote_your_apps_for_free">Promote your apps for free</h4>
+    </div>
+    <div class="col-6of12">
+<h5 id="promote_your_apps_for_free">Promote your apps for free</h5>
 <p>Cross-sell your other apps (or your friend’s apps) to your existing users,
 using free AdMob <a href="https://support.google.com/admob/answer/3210452">house ads</a>.</p>
-</div>
+    </div>
+  </div>
 </div>
 
-<div style="display:inline-block">
-<h3 id="drive_more_in-app_purchases_and_downloads">Drive more in-app purchases and downloads</h3>
-
-<div class="col-6">
-<h4 id="analytics_for_apps">Analytics for apps</h4>
+<h2 id="understand_users">Understand your users</h2>
+<div class="wrap">
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-6of12">
+<h5 id="analytics_for_apps">Analytics for apps</h5>
 <p>Analyze your app’s performance from within AdMob with Google Analytics.
 Discover where people are downloading your app, and the features they use the
 most in real time.</p>
-</div>
-
-<div class="col-6">
-<h4 id="flow_visualization_reports">Flow visualization reports</h4>
+    </div>
+    <div class="col-6of12">
+<h5 id="flow_visualization_reports">Flow visualization reports</h5>
 <p>In Analytics, see how people are navigating through your app with graphical
 <a href="https://support.google.com/analytics/answer/2519986">flow reports</a>.
 View the path they take to making a purchase, and the point where they exit
 the app, plus much more.</p>
-</div>
+    </div>
+  </div>
 </div>
 
 
-<h2 id=tips>Tips</h2>
+<div style="<h2 id=tips>Tips</h2>
 
 <ul>
   <li> Place ads wisely, they shouldn't be too intrusive but still need to be clearly
diff --git a/docs/html/distribute/monetize/index.jd b/docs/html/distribute/monetize/index.jd
index 7350a24..dc5c704 100644
--- a/docs/html/distribute/monetize/index.jd
+++ b/docs/html/distribute/monetize/index.jd
@@ -1,4 +1,4 @@
-page.title=Monetize
+page.title=Earn
 section.landing=true
 nonavpage=true
 
@@ -17,20 +17,17 @@
   help you track where your money is coming from.
 </p>
 
-<div class="dynamic-grid">
-
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/monetize"
     data-cardSizes="6x6"
     data-maxResults="9">
   </div>
 
-<h3>Related resources</h3>
+<!-- <h2>Related resources</h2>
 
   <div class="resource-widget resource-flow-layout col-16"
     data-query="tag:monetizing"
-    data-sortOrder="-timestamp"
-    data-cardSizes="6x3"
-    data-maxResults="6">
-  </div>
-</div>
+    data-cardSizes="6x2"
+    data-sortOrder="random"
+    data-maxResults="3">
+  </div> -->
\ No newline at end of file
diff --git a/docs/html/distribute/monetize/payments.jd b/docs/html/distribute/monetize/payments.jd
index 55c289f..187f872 100644
--- a/docs/html/distribute/monetize/payments.jd
+++ b/docs/html/distribute/monetize/payments.jd
@@ -1,5 +1,5 @@
 page.title=Convenient, Frictionless Purchasing
-page.image=/distribute/images/payment-method.jpg
+page.image=
 page.metaDescription=Users can purchase instantly with a choice of payment methods.
 page.tags="google play", "payments", "gift card"
 
diff --git a/docs/html/distribute/tools/index.jd b/docs/html/distribute/tools/index.jd
index c8f0212..24c3398 100644
--- a/docs/html/distribute/tools/index.jd
+++ b/docs/html/distribute/tools/index.jd
@@ -9,49 +9,39 @@
   users, and monetize your investment.
 </p>
 
-<div class="dynamic-grid">
-
-  <h3>Publishing and Launch</h3>
+  <h2>Publishing and Launch</h2>
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/tools/checklists"
     data-cardSizes="9x6"
     data-maxResults="2">
   </div>
 
-<h3>Marketing Tools</h3>
+  <h2>Marketing Tools</h2>
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/tools/promote"
     data-cardSizes="6x6"
     data-maxResults="3">
   </div>
 
-  <h3>Developer Support</h3>
+  <h2>Developer Support</h2>
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/tools/support"
     data-cardSizes="6x6"
     data-maxResults="3">
   </div>
 
-  <h3>Developer News</h3>
+  <h2>Developer News</h2>
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/tools/news"
     data-cardSizes="9x6"
     data-maxResults="2">
   </div>
 
-  <h3>More</h3>
+  <h2>More</h2>
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/tools/more"
     data-cardSizes="6x6"
     data-maxResults="3">
   </div>
 
-<!--  <h3>Related Resources</h3>
-  <div class="resource-widget resource-stack-layout col-16"
-    data-query="tag:developersupport"
-    data-sortOrder="-timestamp"
-    data-numStacks="3"
-    data-maxResults="6">
-  </div> -->
 
-</div>
diff --git a/docs/html/distribute/users/house-ads.jd b/docs/html/distribute/users/house-ads.jd
new file mode 100644
index 0000000..d662fb2
--- /dev/null
+++ b/docs/html/distribute/users/house-ads.jd
@@ -0,0 +1,61 @@
+page.title=Cross-Sell to Users with House Ads
+page.metaDescription=Tap into your existing user base to increase downloads and increase conversions.
+page.tags="google", "identity", "signin"
+page.image=distribute/images/advertising.jpg
+
+@jd:body
+
+<p>One of the fastest ways to accumulate downloads or increase conversions is to tap into your
+existing user base. These users know your products and are a receptive audience for your other
+apps and in-app products.</p>
+
+<h3>Promote your apps for free</h3>
+
+<p>AdMob's house ads let you cross-sell your other apps (or your friend’s apps) to your
+existing users, and it's a free service.</p>
+
+<h3>Sell more in-app purchases</h3>
+
+<p>Intelligently promote your in-app purchases to the users most likely to buy them, with
+AdMob’s free in-app purchase house ad format.</p>
+
+<p>Get started <a href="https://developers.google.com/identity/sign-in/">integrating
+Google sign-in into your apps and games</a>.</p>
+
+<div class="wrap">
+  <div class="cols" style="margin:1em auto;">
+    <div class="col-8of12">
+     <img src="{@docRoot}images/distribute/house-ads.png" style="padding-top:1em;">
+    </div>
+  </div>
+</div>
+
+<p><a href="http://www.google.com/ads/admob/#subid=us-en-et-dac">Sign-up for AdMob</a> today
+and start using the <a href="https://developer.android.com/google/play-services/ads.html">Google
+Mobile Ads SDK</a> included in Google Play services to show ads in your app with a few lines of
+code. Then create your <a href="https://support.google.com/admob/answer/3210442?hl=en">house
+ad campaigns</a>.</p>
+
+<h2>Tips</h2>
+
+<ul>
+  <li>AdMob automatically figures out which of your users are likely to spend to optimize which
+  users see the ads.</li>
+  <li>Place ads wisely, they shouldn't be too intrusive but still need to be clearly visible to
+  attract clickthroughs.</li>
+  <li>Remember that ads form part of your app and must match its age rating.</li>
+  <li>Use the impression goals feature of AdMob house ads to set limits on the number of ads
+  served. This is useful if you want to run ad campaigns in your app from other developers.</li>
+</ul>
+
+
+<h2 style="clear:both" id="related-resources">Related Resources</h2>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/houseads"
+  data-sortorder="-timestamp"
+  data-cardsizes="6x3"
+  data-maxresults="6">
+</div>
+
+
diff --git a/docs/html/distribute/users/index.jd b/docs/html/distribute/users/index.jd
index a810f36..a3f8d01 100644
--- a/docs/html/distribute/users/index.jd
+++ b/docs/html/distribute/users/index.jd
@@ -10,21 +10,23 @@
   developers. These best practices are critical to your app or game’s success.
 </p>
 
-<div class="dynamic-grid">
-
 <div class="resource-widget resource-flow-layout landing col-16"
   data-query="collection:distribute/users"
   data-cardSizes="6x6"
   data-maxResults="6">
 </div>
+<div class="resource-widget resource-flow-layout landing col-16"
+  data-query="collection:distribute/users"
+  data-cardSizes="9x3"
+  data-maxResults="16">
+</div>
 
-<h3>Related resources</h3>
+<!-- <h2>Related resources</h2>
 
   <div class="resource-widget resource-flow-layout col-16"
-    data-query="type:youtube+tag:users,tag:global,type:blog+tag:users"
-    data-sortOrder="-timestamp"
-    data-cardSizes="6x3"
-    data-maxResults="6">
-  </div>
-  
-</div>
+    data-query="tag:users"
+    data-sortOrder="random"
+    data-cardSizes="6x2"
+    data-maxResults="3">
+  </div> -->
+
diff --git a/docs/html/distribute/users/ota-installs.jd b/docs/html/distribute/users/ota-installs.jd
new file mode 100644
index 0000000..f703257
--- /dev/null
+++ b/docs/html/distribute/users/ota-installs.jd
@@ -0,0 +1,51 @@
+page.title=Offer Over-the-air Installs
+page.metaDescription=Let users send your app directly to their devices when they sign in with Google.
+page.tags="google", "identity", "installs"
+page.image=images/cards/google-sign-in_2x.png
+
+
+@jd:body
+
+<p>Google sign-in is a trusted registration system that's familiar to users and
+consistent across devices. With minimal effort, you can improve your sign-in conversion
+with a fast and secure authentication option for users. And by using Google sign-in,
+you can offer users the option to send your app directly to their Android devices when
+they sign-in, without the need for them to visit the Play store. Using this approach,
+some developers have seen app installation acceptance rates of 40%.</p>
+
+<p>Get started with <a href="https://developers.google.com/identity/sign-in/android/">
+Google sign-in for Android</a> and then enable <a
+href="https://developers.google.com/identity/sign-in/web/android-app-installs">over-the-air
+installs</a> for your web site.</p>
+
+<div class="wrap">
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-8of12 col-push-1of12">
+     <img src="{@docRoot}images/distribute/ota-installs.gif">
+    </div>
+  </div>
+</div>
+
+
+<h2>Tips</h2>
+
+<ul>
+  <li>Adding Google sign-in to your app can increase conversions by reducing the burden
+  and friction of sign-in, while helping users keep their accounts secure.</li>
+  <li>Focus on the quality of your app to ensure that it passes the quality threshold for
+  over-the-air installation.</li>
+  <li>Measure impressions of the Android install prompt, installs, and success rate by
+  day, week, and month with Platform Insights.</li>
+</ul>
+
+
+<h2 style="clear:both" id="related-resources">Related Resources</h2>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/otas"
+  data-sortorder="-timestamp"
+  data-cardsizes="9x3"
+  data-maxresults="4">
+</div>
+
+
diff --git a/docs/html/distribute/users/promote-with-ads.jd b/docs/html/distribute/users/promote-with-ads.jd
index d71b8c9..3456c66 100644
--- a/docs/html/distribute/users/promote-with-ads.jd
+++ b/docs/html/distribute/users/promote-with-ads.jd
@@ -11,56 +11,67 @@
 
 <h2 id=drive_installs>Drive installs</h2>
 
-<p><a href="http://adwords.google.com">AdWords</a> promotes your app to interested users where they spend time on phones and
+<p><a href="http://adwords.google.com">AdWords</a> promotes your app to interested
+users where they spend time on phones and
 tablets – with app install ads on Google Search, YouTube, Gmail, and within
 apps and across the web on  the Google Display Network. AdWords is a powerful
 way to scale app promotion across Google networks and find customers that are
 most likely to install your app. </p>
 
-<p><a href="https://support.google.com/adwords/answer/6032059">Get started with AdWords app install ads</a>.</p>
+<p><a href="https://support.google.com/adwords/answer/6032059">Get started with AdWords
+app install ads</a>.</p>
 
-<div style="display:inline-block">
- <div class="figure-left" style="width:40%;">
+
+
+<div class="wrap">
+  <div class="cols" style="margin-top:1em;">
+    <div class="col-4of12">
    <h3>From Google Play</h3>
-   <img src="/images/distribute/promote_ads_play.png">
-    <p class="figure-caption">Search ads on Google Play are still undergoing testing and not yet available to
-buy. <a href="http://android-developers.blogspot.com/2015/02/a-new-way-to-promote-your-app-on-google.html">Find out more</a>.</p>
-  </div>
-  <div class="figure-right" style="width:40%;">
-    <h3>From apps</h3>
+    <img src="/images/distribute/promote_ads_play.png">
+    <p class="figure-caption">Search ads on Google Play are still undergoing testing and
+    not yet available to buy. <a
+    href="http://android-developers.blogspot.com/2015/02/a-new-way-to-promote-your-app-on-google.html">Find
+    out more</a>.</p>
+    </div>
+    <div class="col-4of12">
+  <h3>From search</h3>
     <img src="/images/distribute/promote_ads_search.png">
-    <p class="figure-caption">Connect with users as they search for content and services provided by your
-app.</p>
-  </div>
-</div>
-
-<div style="display:inline-block">
- <div class="figure-left" style="width:40%;">
+    <p class="figure-caption">Connect with users as they search for content and services
+    provided by your app.</p>
+    </div>
+    <div class="col-4of12">
    <h3>From YouTube</h3>
    <img src="/images/distribute/promote_ads_youtube.png">
     <p class="figure-caption">Promote your app when users are watching related videos.</p>
+    </div>
   </div>
-  <div class="figure-right" style="width:40%;">
+</div>
+
+<div class="wrap">
+  <div class="cols" style="margin-top:1em;">
+    <div class="col-4of12">
     <h3>From apps</h3>
     <img src="/images/distribute/promote_ads_apps.png">
-    <p class="figure-caption">Reach users while they’re engaged with apps and games across the AdMob network.</p>
-  </div>
-</div>
-
-<div style="display:inline-block">
- <div class="figure-left" style="width:40%;">
+    <p class="figure-caption">Reach users while they’re engaged with apps and games across the
+    AdMob network.</p>
+    </div>
+    <div class="col-4of12">
    <h3>From the web</h3>
    <img src="/images/distribute/promote_ads_web.png">
-    <p class="figure-caption">Reach users while they’re engaged with websites across the Google Display Network.</p>
-  </div>
-  <div class="figure-right" style="width:40%;">
+    <p class="figure-caption">Reach users while they’re engaged with websites across the Google
+    Display Network.</p>
+    </div>
+    <div class="col-4of12">
     <h3>From Gmail</h3>
     <img src="/images/distribute/promote_ads_gmail.png">
-    <p class="figure-caption">Promote your app while users communicate and get things done in Gmail.</p>
+    <p class="figure-caption">Promote your app while users communicate and get things done in
+    Gmail.</p>
+    </div>
   </div>
 </div>
 
-<h3>Tips</h3>
+
+<h2>Tips</h3>
 
 <ul>
   <li> Estimate how much an app user is worth to your business, so that you can work
@@ -89,21 +100,25 @@
 remind them of key features and encourage them to try your app again, or help
 them complete an activity they didn't know your app could handle.</p>
 
-<div>
- <div class="figure-left" style="width:46%;">
+
+<div class="wrap">
+  <div class="cols" style="margin-top:1em;">
+    <div class="col-4of12">
    <h3>From search</h3>
    <img src="/images/distribute/promote_ads.png">
     <p class="figure-caption">Add deep links to your app, then bring users straight
     to relevant app content when they’re searching.</p>
-  </div>
-  <div class="figure-right" style="width:46%;">
+    </div>
+    <div class="col-4of12">
     <h3>From apps</h3>
     <img src="/images/distribute/promote_ads_inapp.png">
     <p class="figure-caption">Use remarketing and deep links to bring users to just the right
     place in your app to re-engage and convert, from other apps and games they love.</p>
+    </div>
   </div>
 </div>
 
+
 <h3>Tips</h3>
 
 <ul>
diff --git a/docs/html/distribute/users/users_toc.cs b/docs/html/distribute/users/users_toc.cs
index 2e796c8..3aa3fe1 100644
--- a/docs/html/distribute/users/users_toc.cs
+++ b/docs/html/distribute/users/users_toc.cs
@@ -29,6 +29,24 @@
     </div>
   </li>
   <li class="nav-section">
+    <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/ota-installs.html">
+          <span class="en">Offer Over-the-air Installs</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/house-ads.html">
+          <span class="en">Cross-Sell to Users with House Ads</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/youtube.html">
+          <span class="en">Drive installs from YouTube</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
     <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/build-buzz.html">
           <span class="en">Build Buzz</span>
         </a>
diff --git a/docs/html/distribute/users/youtube.jd b/docs/html/distribute/users/youtube.jd
new file mode 100644
index 0000000..0be6584
--- /dev/null
+++ b/docs/html/distribute/users/youtube.jd
@@ -0,0 +1,34 @@
+page.title=Drive installs from YouTube
+page.metaDescription=Bring users from videos to your store listing with a merchandise card available on YouTube.
+page.image=images/cards/card-youtube_2x.png
+page.tags="users, youtube, cards, videos"
+@jd:body
+
+<p>Now you can bring users who discover your app videos on YouTube to your store listing with a merchandise card, one of several card types available to add to YouTube videos. Once published the presence of the merchandise card is indicated in the video with an information icon. When a viewer opens the card they follow the link to your app on the Play Store, where they can install your app.</p>
+
+<div class="wrap" style="margin:2em auto">
+  <div class="cols">
+    <div class="col-9of12">
+      <img src="{@docRoot}images/distribute/youtube-card-example.png">
+    </div>
+  </div>
+</div>
+
+<p>Get started <a href="https://support.google.com/youtube/answer/6140493">adding merchandise cards to your uploaded videos</a>.</p>
+
+<h2>Tips</h2>
+<ul>
+<li>Don’t indicate the location of a card within your video, cards might be positioned differently on different devices.</li>
+<li>When you add cards, featured video or playlist highlights in your video are hidden. </li>
+<li>In order to display cards, your account needs to be in good standing.</li>
+<li>Performance reporting for cards is available in YouTube Analytics.</li>
+<li>Cards work better when they're not too close to each other. Try spacing them out.</li>
+</ul>
+
+<h2 id="related-resources">Related resources</h2>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/youtube"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
diff --git a/docs/html/google/index.jd b/docs/html/google/index.jd
index 1ebb9f8..9df09e1 100644
--- a/docs/html/google/index.jd
+++ b/docs/html/google/index.jd
@@ -1,7 +1,7 @@
 fullpage=true
 page.title=Google Services
 section.landing=true
-meta.tags="beautifulapps, design, ux, patterns, holo, appquality, landing"
+meta.tags="google, play, services, maps, location, gcm, messaging, places"
 header.hide=1
 footer.hide=1
 @jd:body
@@ -16,25 +16,21 @@
       <div class="col-1of2 col-pull-1of2">
         <h1 class="dac-hero-title">Build better apps with Google</h1>
         <p class="dac-hero-description">
-        Add powerful capabilities to your apps, quickly, at low cost. Simplify development,
-grow your user base, and monetize more effectively with Google Play services. 
-        </p>
-        <a class="dac-hero-cta" href="https://www.google.com/design/spec/material-design/introduction.html">
+          Take advantage of the latest Google technologies through a single set of APIs, delivered
+          across Android devices worldwide as part of Google Play services. </p>
+          <p class="dac-hero-description">Start by setting up the Google Play services library,
+          then build with the APIs you need. </p>
+
+        <a class="dac-hero-cta" href="https://developers.google.com/android/guides/">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Get Started with Google Play services
+          Set up Google Play services
         </a><br>
-        <a class="dac-hero-cta" href="https://www.google.com/design/spec/resources/color-palettes.html">
+        <a class="dac-hero-cta" href="https://developers.google.com/android/reference/">
           <span class="dac-sprite dac-auto-chevron"></span>
           API Reference
         </a><br>
       </div>
     </div>
-    <div class="dac-section dac-small">
-      <!--<div class="resource-widget resource-flow-layout col-16"
-           data-query="collection:google/landing/google"
-           data-cardSizes="6x2"
-           data-maxResults="6"></div>-->
-    </div>
   </div>
 </section>
 <div class="wrap dac-offset-parent">
@@ -42,42 +38,52 @@
     <i class="dac-sprite dac-arrow-down-gray"></i>
   </a>
 </div>
+
 <section class="dac-section dac-gray dac-small dac-invert" id="latest"><div class="wrap">
   <h2 class="norule">Latest</h2>
   <div class="resource-widget resource-flow-layout col-16"
        data-query="type:blog+tag:googleservices+tag:featured+tag:develop"
        data-cardSizes="6x6"
        data-maxResults="3"></div>
-</div></section>
-
-
+  </div>
+</section>
 
 <section class="dac-section dac-light"><div class="wrap">
   <h1 class="dac-section-title">Google APIs and services</h1>
   <div class="dac-section-subtitle">
-    Design around Android&apos;s capabilities and conventions to give users the best experience.
+    Add the latest Google-powered features to enrich your app,
+          grow your user base, and monetize. 
   </div>
   <div class="resource-widget resource-flow-layout col-16"
        data-query="collection:google/landing/services"
        data-cardSizes="6x6"
        data-maxResults="6"></div>
   <ul class="dac-section-links">
-    <li class="dac-section-link"><a href="https://developers.google.com/">
+    <li class="dac-section-link"><a href="https://developers.google.com/android/">
       <span class="dac-sprite dac-auto-chevron"></span>
       More Google services for Android
     </a></li>
   </ul>
-</div></section>
+  </div>
+</section>
 
+<section class="dac-section dac-gray dac-small dac-invert" id="latest"><div class="wrap">
+  <h2 class="norule">Latest</h2>
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="collection:google/landing/videos"
+       data-cardSizes="6x6"
+       data-maxResults="3"></div>
+  </div>
+</section>
 
 <section class="dac-section dac-invert dac-darken-bg" style="background-image: url(/images/distribute/google-play-bg.jpg)"><div class="wrap">
   <h1 class="dac-section-title">Google Play developer tools</h1>
   <div class="dac-section-subtitle">
-    Scale your operations. Essential downloads, stencils, and tools to help you create your design.
+    Scale your publishing, manage your catalog, and build revenue using Google Play developer tools. 
   </div>
   <div class="resource-widget resource-flow-layout col-16"
        data-query="collection:google/landing/googleplay"
-       data-cardSizes="6x6"
+       data-cardSizes="6x3"
        data-maxResults="6"></div>
 
   <ul class="dac-section-links">
diff --git a/docs/html/google/play/billing/billing_subscriptions.jd b/docs/html/google/play/billing/billing_subscriptions.jd
index 51fec09..e412a9d 100644
--- a/docs/html/google/play/billing/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/billing_subscriptions.jd
@@ -1,7 +1,7 @@
 page.title=In-app Subscriptions
 parent.title=In-app Billing
 parent.link=index.html
-page.metaDescription=Subscriptions let you sell content or features in your app with automated, recurring billing.
+page.metaDescription=Create a steady revenue stream by selling subscriptions to your content.
 page.image=/images/play_dev.jpg
 page.tags="subscriptions, billing, inapp, iap"
 meta.tags="monetization, inappbilling, subscriptions"
diff --git a/docs/html/google/play/billing/index.jd b/docs/html/google/play/billing/index.jd
index c671c71..ae6e222 100644
--- a/docs/html/google/play/billing/index.jd
+++ b/docs/html/google/play/billing/index.jd
@@ -1,5 +1,5 @@
-page.title=Google Play In-app Billing
-page.metaDescription=In-app Billing lets you sell digital content as one-time purchases or subscriptions.
+page.title=In-app Billing
+page.metaDescription=Sell digital content as one-time purchases inside your app.
 page.image=/images/play_dev.jpg
 meta.tags="monetizing, inappbilling, subscriptions"
 page.tags="billing, inapp, iap"
@@ -24,7 +24,9 @@
     period.</li>
   <li><strong>IAB Sandbox</strong>&mdash;The In-app Billing Sandbox now supports
     testing subscription purchases.</li>
-  <li><strong>IAB v2 shutdown</strong>&mdash;In-app Billing v2 API is deprecated and will be shut down in January 2015. If your app is still using In-app Billing v2, please migrate to the v3 API as soon as possible.</li>
+  <li><strong>IAB v2 shutdown</strong>&mdash;In-app Billing v2 API is deprecated
+    and will be shut down in January 2015. If your app is still using In-app Billing
+    v2, please migrate to the v3 API as soon as possible.</li>
   <li><strong>Seasonal subscriptions</strong>&mdash;You can now set up a
     recurring <a href="billing_subscriptions.html#user-billing">seasonal
     subscription</a> that starts and ends on the same date each year (for
diff --git a/docs/html/images/cards/card-analytics_2x.png b/docs/html/images/cards/card-analytics_2x.png
new file mode 100644
index 0000000..da62659
--- /dev/null
+++ b/docs/html/images/cards/card-analytics_2x.png
Binary files differ
diff --git a/docs/html/images/cards/card-android-work_2x.png b/docs/html/images/cards/card-android-work_2x.png
new file mode 100644
index 0000000..ac8b9280
--- /dev/null
+++ b/docs/html/images/cards/card-android-work_2x.png
Binary files differ
diff --git a/docs/html/images/cards/card-youtube_2x.png b/docs/html/images/cards/card-youtube_2x.png
new file mode 100644
index 0000000..28bdd89
--- /dev/null
+++ b/docs/html/images/cards/card-youtube_2x.png
Binary files differ
diff --git a/docs/html/images/develop/hero_image_studio5.png b/docs/html/images/develop/hero_image_studio5.png
new file mode 100644
index 0000000..08fa57c
--- /dev/null
+++ b/docs/html/images/develop/hero_image_studio5.png
Binary files differ
diff --git a/docs/html/images/develop/hero_image_studio5_2x.png b/docs/html/images/develop/hero_image_studio5_2x.png
new file mode 100644
index 0000000..f119749
--- /dev/null
+++ b/docs/html/images/develop/hero_image_studio5_2x.png
Binary files differ
diff --git a/docs/html/images/develop/studio-open.png b/docs/html/images/develop/studio-open.png
deleted file mode 100644
index 2e0f599e..0000000
--- a/docs/html/images/develop/studio-open.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/distribute/android-work.jpg b/docs/html/images/distribute/android-work.jpg
new file mode 100644
index 0000000..91f742b
--- /dev/null
+++ b/docs/html/images/distribute/android-work.jpg
Binary files differ
diff --git a/docs/html/images/distribute/gpfw_business.png b/docs/html/images/distribute/gpfw_business.png
new file mode 100644
index 0000000..d395b4e
--- /dev/null
+++ b/docs/html/images/distribute/gpfw_business.png
Binary files differ
diff --git a/docs/html/images/distribute/gpfw_developer.png b/docs/html/images/distribute/gpfw_developer.png
new file mode 100644
index 0000000..c0f0d26
--- /dev/null
+++ b/docs/html/images/distribute/gpfw_developer.png
Binary files differ
diff --git a/docs/html/images/distribute/house-ads.png b/docs/html/images/distribute/house-ads.png
new file mode 100644
index 0000000..f4df870
--- /dev/null
+++ b/docs/html/images/distribute/house-ads.png
Binary files differ
diff --git a/docs/html/images/distribute/ota-installs.gif b/docs/html/images/distribute/ota-installs.gif
new file mode 100644
index 0000000..85e40da
--- /dev/null
+++ b/docs/html/images/distribute/ota-installs.gif
Binary files differ
diff --git a/docs/html/images/distribute/signin-apps.png b/docs/html/images/distribute/signin-apps.png
new file mode 100644
index 0000000..9891acd
--- /dev/null
+++ b/docs/html/images/distribute/signin-apps.png
Binary files differ
diff --git a/docs/html/images/distribute/signin-seamless.png b/docs/html/images/distribute/signin-seamless.png
new file mode 100644
index 0000000..01b9d73
--- /dev/null
+++ b/docs/html/images/distribute/signin-seamless.png
Binary files differ
diff --git a/docs/html/images/distribute/signin-secure.png b/docs/html/images/distribute/signin-secure.png
new file mode 100644
index 0000000..3baad23
--- /dev/null
+++ b/docs/html/images/distribute/signin-secure.png
Binary files differ
diff --git a/docs/html/images/distribute/youtube-card-example.png b/docs/html/images/distribute/youtube-card-example.png
new file mode 100644
index 0000000..e5d77f9
--- /dev/null
+++ b/docs/html/images/distribute/youtube-card-example.png
Binary files differ
diff --git a/docs/html/images/play_dev.jpg b/docs/html/images/play_dev.jpg
index 6aae165..92513b7 100644
--- a/docs/html/images/play_dev.jpg
+++ b/docs/html/images/play_dev.jpg
Binary files differ
diff --git a/docs/html/images/play_dev_old.jpg b/docs/html/images/play_dev_old.jpg
new file mode 100644
index 0000000..6aae165
--- /dev/null
+++ b/docs/html/images/play_dev_old.jpg
Binary files differ
diff --git a/docs/html/images/versions/notification-headsup.png b/docs/html/images/versions/notification-headsup.png
index 7c374c8..623b225 100644
--- a/docs/html/images/versions/notification-headsup.png
+++ b/docs/html/images/versions/notification-headsup.png
Binary files differ
diff --git a/docs/html/images/versions/rivalknights.png b/docs/html/images/versions/rivalknights.png
index 6b467ef..6137fc4 100644
--- a/docs/html/images/versions/rivalknights.png
+++ b/docs/html/images/versions/rivalknights.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 71f6d58..c0a5b4b 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -1,5 +1,4 @@
 fullpage=true
-page.viewport_width=970
 excludeFromSuggestions=true
 page.metaDescription=The official site for Android developers. Provides the Android SDK and documentation for app developers and designers.
 page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" />
@@ -31,13 +30,12 @@
   </div><!-- end .wrap -->
 </div><!-- end .actions-bar -->
 
-<div class="dac-hero-carousel" data-carousel-query="collection:distribute/landing/carousel">
-</div>
+
 
 <section class="dac-section dac-section-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
-    See what’s new or find the resources to get you started with designing and developing for Android.
+    Resources to get you started with designing and developing for Android.
   </div>
   <div class="resource-widget resource-flow-layout col-16"
        data-query="collection:index/primary"
@@ -45,11 +43,14 @@
        data-maxResults="3"></div>
 </div></section>
 
+<div class="dac-hero-carousel" data-carousel-query="collection:distribute/landing/carousel">
+</div>
+
 <section class="dac-section dac-gray"><div class="wrap">
   <div class="cols"><div class="col-10of12 col-push-1of12">
     <h1 class="dac-section-title">Build for a Multi-Screen World</h1>
     <div class="dac-section-subtitle">
-      Android runs on hundreds of millions of handheld devices around the world,
+      Android runs on billions of handheld devices around the world,
       and it now supports these exciting, new form-factors.
     </div>
   </div></div>
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index a293131..4950d97 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -123,10 +123,18 @@
     "resources": [
       "https://developers.google.com/analytics/devguides/collection/android/",
       "https://developers.google.com/maps/documentation/android/",
-      "https://developers.google.com/+/mobile/android/sign-in",
-      "https://developers.google.com/places/android/",
+      "https://developers.google.com/identity/sign-in/android/",
+      "https://developers.google.com/mobile-ads-sdk/download",
       "https://developers.google.com/gcm/android/",
-      "https://developers.google.com/maps/documentation/android/"
+      "https://developers.google.com/app-indexing/"
+    ]
+  },
+  "google/landing/videos": {
+    "title": "",
+    "resources": [
+      "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": {
@@ -203,7 +211,7 @@
       "http://youtu.be/vzvpcEffvaE"
     ]
   },
-  "launch/static": {
+/*  "launch/static": {
     "title": "",
     "resources": [
       "http://www.youtube.com/watch?v=1RIz-cmTQB4",
@@ -221,7 +229,7 @@
       "distribute/users/know-your-user.html",
       "distribute/googleplay/developer-console.html"
     ]
-  },
+  }, */
   "launch/static/ja": {
     "title": "",
     "resources": [
@@ -272,8 +280,18 @@
       "distribute/googleplay/auto.html",
       "distribute/googleplay/tv.html",
       "distribute/googleplay/wear.html",
+      "distribute/googleplay/cardboard.html",
+      "distribute/googleplay/cast.html",
       "distribute/googleplay/edu/about.html",
-      "distribute/googleplay/families/about.html"
+      "distribute/googleplay/families/about.html",
+      "distribute/googleplay/work/about.html"
+    ]
+  },
+  "distribute/googleplay/gpfw": {
+    "resources": [
+      "http://www.android.com/work/",
+      "https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
+      "training/enterprise/index.html"
     ]
   },
   "distribute/essentials": {
@@ -304,6 +322,9 @@
       "distribute/users/expand-to-new-markets.html",
       "distribute/users/promote-with-ads.html",
       "distribute/users/appindexing.html",
+      "distribute/users/ota-installs.html",
+      "distribute/users/house-ads.html",
+      "distribute/users/youtube.html",
       "distribute/users/build-buzz.html",
       "distribute/users/build-community.html"
     ]
@@ -317,6 +338,7 @@
       "distribute/engage/deep-linking.html",
       "distribute/engage/ads.html",
       "distribute/engage/intents.html",
+      "distribute/engage/appindexing.html",
       "distribute/engage/analytics.html",
       "distribute/engage/game-services.html",
       "distribute/engage/app-updates.html",
@@ -503,7 +525,7 @@
   "distribute/googleplay/cardboard": {
     "title": "Google Cast",
     "resources": [
-      "https://www.google.com/get/cardboard/",
+      "https://www.google.com/get/cardboard/get-cardboard/",
       "https://developers.google.com/cardboard/android/download",
       "http://www.google.com/design/spec-vr"
     ]
@@ -630,7 +652,33 @@
     "resources": [
       "https://developers.google.com/app-indexing/",
       "https://developers.google.com/app-indexing/webmasters/details",
-      "distribute/engage/search.html"
+      "distribute/engage/appindexing.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",
+      "http://support.google.com/googleplay/android-developer/topic/2985714",
+      "http://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": {
@@ -910,10 +958,9 @@
   "distribute/engage/gplus": {
     "title": "",
     "resources": [
-      "google/play-services/plus.html",
-      "google/play-services/games.html",
-      "https://developers.google.com/+/mobile/android/share/interactive-post",
-      "https://developers.google.com/+/mobile/android/share/deep-link"
+      "distribute/users/ota-installs.html",
+      "https://developers.google.com/identity/sign-in/android/people",
+      "https://developers.google.com/+/mobile/android/"
     ]
   },
   "distribute/engage/community": {
@@ -1523,4 +1570,4 @@
       "samples/BasicManagedProfile/index.html"
     ]
   }
-}
+}
\ No newline at end of file
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
index cf1da97..f318668 100644
--- a/docs/html/jd_extras.js
+++ b/docs/html/jd_extras.js
@@ -81,11 +81,11 @@
     "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/",
+    "url":"https://www.google.com/get/cardboard/get-cardboard/",
     "group":"",
     "keywords": ["carboard","vr"],
     "tags": [],
-    "image":"images/cards/card-cardboard_2x.jpg",
+    "image":"images/cards/card-cardboard_2x.png",
     "type":"Guide"
   },
     {
@@ -110,9 +110,6 @@
     "image":"images/cards/card-cardboard_2x.png",
     "type":"Design"
   },
-
-
-
   {
     "title":"Maps",
     "titleFriendly":"",
@@ -146,22 +143,6 @@
     "image":"images/gcm/gcm-logo.png",
     "type":"Guide"
   },
-   
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
   {
     "title":"ClassDojo Developer Story",
     "titleFriendly":"",
@@ -315,6 +296,30 @@
     "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":"http://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":"http://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.",
@@ -1243,27 +1248,13 @@
     "url": "http://www.google.com/analytics/mobile/",
     "timestamp": 1383243492000,
     "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Google Mobile App Analytics",
+    "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",
+    "type": "Guide",
     "titleFriendly": ""
   },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#engagement",
-    ],
-    "url": "https://developers.google.com/app-indexing/",
-    "timestamp": 1383243492000,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/search_64dp.png",
-    "title": "Sign Up for App Indexing",
-    "summary": "Surface your app content in Google seaerch. Deep link direct to your apps.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
+
 
   {
     "lang": "en",
@@ -1284,21 +1275,6 @@
     "lang": "en",
     "group": "",
     "tags": [
-      "#googleplus",
-    ],
-    "url": "https://developers.google.com/+/mobile/android/people",
-    "timestamp": 1383243492000,
-    "image": "images/google/gps-googleplus.png",
-    "title": "Google Sign In",
-    "summary": "After you let users sign in with Google, you can access their age range, language, public profile information, and people that they have circled.",
-    "keywords": ["googleplus"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
       "#gcm",
     ],
     "url": "http://developer.chrome.com/apps/cloudMessagingV2",
@@ -1373,12 +1349,12 @@
     "lang": "en",
     "group": "",
     "tags": [],
-    "url": "https://developers.google.com/+/mobile/android/sign-in",
+    "url": "https://developers.google.com/+/mobile/android/",
     "timestamp": 1194884220000,
     "image": 'images/google/gps-googleplus.png',
-    "title": "Sign-in with Google",
-    "summary": "Get users into your app quickly and securely.",
-    "keywords": ["signin", "Google+"],
+    "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": ""
   },
@@ -1596,10 +1572,9 @@
     "tags": ["monetize", "ads"],
     "url": "http://support.google.com/googleplay/android-developer/topic/2985714",
     "timestamp": null,
-    "image": "http://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/play_64dp.png",
+    "image":"images/play_dev.jpg",
     "title": "Policy Center: Ads",
-    "summary": "Introduction to ads and system interference policies in Google Play",
+    "summary": "Introduction to ads and system interference policies in Google Play.",
     "keywords": ["ads"],
     "type": "distribute",
     "titleFriendly": ""
@@ -1607,6 +1582,32 @@
   {
     "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://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,
@@ -1676,7 +1677,7 @@
     "url": "https://developers.google.com/analytics/devguides/collection/android/",
     "timestamp": null,
     "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Mobile App Analytics",
+    "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",
@@ -2395,7 +2396,7 @@
     "tags": [],
     "url": "https://support.google.com/adwords/answer/6032059",
     "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/admob_64dp.png",
+    "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"],
@@ -2408,7 +2409,7 @@
     "tags": [],
     "url": "https://support.google.com/adwords/answer/6167164",
     "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/admob_64dp.png",
+    "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"],
@@ -2452,23 +2453,15 @@
     "type": "distribute",
     "titleFriendly": ""
   },
-
-
-
-
-
-
-
-
   {
     "lang": "en",
     "group": "",
     "tags": [],
     "url": "https://support.google.com/admob/topic/2784623",
     "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/admob_64dp.png",
+    "image": "distribute/images/advertising.jpg",
     "title": "Set up your AdMob account",
-    "summary": "Guide to setting up your account so that you get the most value.",
+    "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": ""
@@ -2479,7 +2472,7 @@
     "tags": [],
     "url": "http://analyticsacademy.withgoogle.com/mobile-app",
     "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/admob_64dp.png",
+    "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"],
@@ -2492,11 +2485,11 @@
     "tags": [],
     "url": "https://developers.google.com/mobile-ads-sdk/download",
     "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/admob_64dp.png",
-    "title": "Google Mobile Ads SDK",
+    "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": "distribute",
+    "type": "Guide",
     "titleFriendly": ""
   },
   {
@@ -2505,7 +2498,7 @@
     "tags": [],
     "url": "https://support.google.com/admob/",
     "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/admob_64dp.png",
+    "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"],
@@ -2518,56 +2511,97 @@
     "tags": [],
     "url": "https://support.google.com/admob/answer/2753860",
     "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/admob_64dp.png",
+    "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": ["appindexing", "search", "getusers"],
+    "tags": [],
     "url": "https://developers.google.com/app-indexing/",
     "timestamp": 1383243492000,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/search_64dp.png",
+    "image": "images/cards/google-search_2x.png",
     "title": "Set Up App Indexing",
-    "summary": "Learn more about how Google Search can help users discover your app, along with other ways you can integrate with Google Search.",
-    "keywords": ["search"],
+    "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": ["appindexing", "search", "getusers"],
+    "tags": [],
     "url": "https://developers.google.com/app-indexing/webmasters/details",
     "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/search_64dp.png",
-    "title": "Verify and Create Deep Links",
-    "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": ["search"],
+    "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": [
-      "appindexing",
-      "search",
-      "getusers",
-    ],
-    "url": "https://support.google.com/admob/answer/2753860",
-    "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/search_64dp.png",
-    "title": "Drive use with Google Search",
-    "summary": "More about how app indexing and deep links can drive users directly to the content in your app. ",
-    "keywords": [],
-    "type": "distribute",
+    "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": ""
+  },
+
+
+
  // TODO remove this?
   {
     "title":"Android Wear Materials",
@@ -2715,7 +2749,7 @@
   {
     "title":"Opportunities & Programs",
     "titleFriendly":"",
-    "summary":"This is a card body place holder text. This is a card body place holder text. This is a card body place holder text.",
+    "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": [],
@@ -2725,6 +2759,56 @@
     "type":"distribute"
   },
   {
+    "title":"Android for Work",
+    "titleFriendly":"",
+    "summary":"Learn more about how Android for Work makes your favorite phones and tablets the perfect business tools.",
+    "url":"http://www.android.com/work/",
+    "group":"",
+    "keywords": ["work", "enterprise", "emm"],
+    "tags": [],
+    "image":"images/cards/card-android-work_2x.png",
+    "lang":"en",
+    "type":"about"
+  },
+  {
+    "title":"Android for Work DevBytes",
+    "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":"http://i1.ytimg.com/vi/jQWB_-o1kz4/maxresdefault.jpg",
+    "lang":"en",
+    "type":"about"
+  },
+  {
+    "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"
+  },
+
+
+  {
     "lang": "ja",
     "title": "Gaming Everywhere",
     "titleFriendly": "",
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index b207e35..5ab4b89 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -1,6 +1,7 @@
 page.title=API Overview
 page.keywords=preview,sdk,compatibility
-sdk.platform.apiLevel=23
+sdk.platform.apiLevel=22-mnc
+page.image=images/cards/card-key-changes_16-9_2x.png
 @jd:body
 
 
diff --git a/docs/html/preview/index.jd b/docs/html/preview/index.jd
index c6c2068..3b5fdbd 100644
--- a/docs/html/preview/index.jd
+++ b/docs/html/preview/index.jd
@@ -22,21 +22,9 @@
           Test your apps and give us feedback!
         </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Preview Program Overview
-        </a><br>
-        <a class="dac-hero-cta" href="{@docRoot}preview/api-overview.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Review the API changes
-        </a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/setup-sdk.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Set up the Preview SDK
-        </a><br>
-        <a class="dac-hero-cta" href="https://code.google.com/p/android-developer-preview/">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Report issues
+          Get started
         </a><br>
 
       </div>
@@ -46,7 +34,20 @@
       <div class="resource-widget resource-flow-layout col-16"
            data-query="collection:preview/landing/resources"
            data-cardSizes="6x2"
-           data-maxResults="6"></div>
+           data-maxResults="3"></div>
     </div>
   </div>
-</section>
\ No newline at end of file
+</section>
+<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>
+  </a>
+</div>
+
+<section class="dac-section dac-gray dac-small dac-invert" id="latest"><div class="wrap">
+  <h2 class="norule">Latest</h2>
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="type:blog+tag:featured+tag:preview"
+       data-cardSizes="6x6"
+       data-maxResults="3"></div>
+</div></section>
diff --git a/docs/html/preview/overview.jd b/docs/html/preview/overview.jd
index 0c8931d..2c79eba 100644
--- a/docs/html/preview/overview.jd
+++ b/docs/html/preview/overview.jd
@@ -1,4 +1,5 @@
 page.title=Preview Program Overview
+page.image=images/cards/card-preview_16-9_2x.png
 
 @jd:body
 
diff --git a/docs/html/preview/setup-sdk.jd b/docs/html/preview/setup-sdk.jd
index 35fab1a..0d6c498 100644
--- a/docs/html/preview/setup-sdk.jd
+++ b/docs/html/preview/setup-sdk.jd
@@ -1,4 +1,5 @@
-page.title=Setting Up the Preview SDK
+page.title=Set Up the Preview SDK
+page.image=images/cards/card-set-up_16-9_2x.png
 @jd:body
 
 
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
index 4be6dd7..3ed1487 100644
--- a/docs/html/preview/support.jd
+++ b/docs/html/preview/support.jd
@@ -1,4 +1,5 @@
 page.title=Support
+page.image=images/cards/card-support_16-9_2x.png
 
 @jd:body
 
diff --git a/docs/html/tools/building/building-cmdline.jd b/docs/html/tools/building/building-cmdline.jd
index 33798a5..0e4c8b2 100644
--- a/docs/html/tools/building/building-cmdline.jd
+++ b/docs/html/tools/building/building-cmdline.jd
@@ -43,7 +43,7 @@
   <p>Whether you're building with the debug or release build type, you need to run
   and build your module. This will create the .apk file that you can install on an emulator or device.
   When you build using the debug build type, the .apk file is automatically signed by the SDK tools
-  with a debug key based on the <code>debuggable true</code> setting in the module's gradle.build file,
+  with a debug key based on the <code>debuggable true</code> setting in the module's build.gradle file,
   so it's instantly ready for installation onto an emulator or attached
   development device. You cannot distribute an application that is signed with a debug key.
   When you build using the release build type, the .apk file is <em>unsigned</em>, so you
@@ -174,7 +174,7 @@
   the build will prompt you for your keystore and alias password when you build using the release
   build type and produce your final application package, which will be ready for distribution.</p>
 
-  <p>To specify your keystore and alias, open the module gradle.build file (found in
+  <p>To specify your keystore and alias, open the module build.gradle file (found in
   the root of the module directory) and add entries for {@code storeFile}, {@code storePassword},
   {@code keyAlias} and {@code keyPassword}.
   For example:</p>
@@ -188,7 +188,7 @@
   <ol>
     <li>Open a command-line and navigate to the root of your module directory.</li>
 
-    <li>Edit the gradle.build file to build your project in release mode:
+    <li>Edit the build.gradle file to build your project in release mode:
       <p><pre>
 ...
 android {
@@ -222,7 +222,7 @@
 
   <p>This creates your Android application .apk file inside the module <code>build/</code>
   directory, named <code><em>&lt;your_module_name&gt;</em>-release.apk</code>. This .apk file has
-  been signed with the private key specified in gradle.build file and aligned with {@code
+  been signed with the private key specified in build.gradle file and aligned with {@code
   zipalign}. It's ready for installation and distribution.</p>
 
   <h3 id="OnceBuilt">Once built and signed in release mode</h3>
diff --git a/docs/html/tools/devices/index.jd b/docs/html/tools/devices/index.jd
index 1ea4c47..6263c8b 100644
--- a/docs/html/tools/devices/index.jd
+++ b/docs/html/tools/devices/index.jd
@@ -5,16 +5,16 @@
  <p>An Android Virtual Device (AVD) is an emulator configuration that lets you model an actual
   device by defining hardware and software options to be emulated by the Android Emulator.</p>
 
-  <p>The easiest way to create an AVD is to use the graphical <a href= 
-  "{@docRoot}tools/devices/managing-avds.html">AVD Manager</a>, which you launch
-  from Eclipse by clicking <strong>Window &gt; AVD Manager</strong>. You can also start the AVD
-Manager from the command line by calling the <code>android</code> tool with the <code>avd</code>
-options, from the <strong>&lt;sdk>/tools/</strong> directory.</p>
+  <p>The easiest way to create an AVD is to use the graphical
+  <a href="{@docRoot}tools/devices/managing-avds.html">AVD Manager</a>, which you launch
+  from Android Studio by clicking <strong>Tools &gt; Android &gt; AVD Manager</strong>. You can
+  also start the AVD Manager from the command line by calling the <code>android</code> tool with
+ the <code>avd</code> options, from the <strong>&lt;sdk>/tools/</strong> directory.</p>
 
   <p>You can also create AVDs on the command line by passing the <code>android</code> tool options.
-  For more information on how to create AVDs in this manner, see <a href= 
-  "{@docRoot}tools/devices/managing-avds-cmdline.html">Managing Virtual
-  Devices from the Command Line</a>.</p>
+  For more information on how to create AVDs in this manner, see
+  <a href="{@docRoot}tools/devices/managing-avds-cmdline.html">Managing Virtual Devices from the
+  Command Line</a>.</p>
 
   <p>An AVD consists of:</p>
 
diff --git a/docs/html/tools/devices/managing-avds-cmdline.jd b/docs/html/tools/devices/managing-avds-cmdline.jd
index ba353c1..c16b1f8 100644
--- a/docs/html/tools/devices/managing-avds-cmdline.jd
+++ b/docs/html/tools/devices/managing-avds-cmdline.jd
@@ -84,8 +84,8 @@
 
 <h2 id="AVDCmdLine">Creating AVDs</h2>
 
-<p>In addition to creating AVDs with the 
-<a href="{@docRoot}tools/devices/managing-avds-cmdline.html">AVD Manager user interface</a>,
+<p>In addition to creating AVDs with the
+<a href="{@docRoot}tools/help/avd-manager.html">AVD Manager user interface</a>,
 you can also create them by passing in command line arguments to the <code>android</code> tool.
 </p>
 
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 2d8b0b2..a999b71 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -558,6 +558,22 @@
     }
 
     /**
+     * Creates a new immutable bitmap backed by ashmem which can efficiently
+     * be passed between processes.
+     *
+     * @hide
+     */
+    public Bitmap createAshmemBitmap() {
+        checkRecycled("Can't copy a recycled bitmap");
+        Bitmap b = nativeCopyAshmem(mFinalizer.mNativeBitmap);
+        if (b != null) {
+            b.setPremultiplied(mRequestPremultiplied);
+            b.mDensity = mDensity;
+        }
+        return b;
+    }
+
+    /**
      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
      * specified width and height are the same as the current width and height of
      * the source bitmap, the source bitmap is returned and no new bitmap is
@@ -1636,6 +1652,7 @@
                                               int nativeConfig, boolean mutable);
     private static native Bitmap nativeCopy(long nativeSrcBitmap, int nativeConfig,
                                             boolean isMutable);
+    private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
     private static native void nativeDestructor(long nativeBitmap);
     private static native boolean nativeRecycle(long nativeBitmap);
     private static native void nativeReconfigure(long nativeBitmap, int width, int height,
diff --git a/graphics/java/android/graphics/drawable/RippleComponent.java b/graphics/java/android/graphics/drawable/RippleComponent.java
index 0412e35..5ba2f93 100644
--- a/graphics/java/android/graphics/drawable/RippleComponent.java
+++ b/graphics/java/android/graphics/drawable/RippleComponent.java
@@ -57,14 +57,19 @@
         mBounds = bounds;
     }
 
+    public void onBoundsChange() {
+        if (!mHasMaxRadius) {
+            mTargetRadius = getTargetRadius(mBounds);
+            onTargetRadiusChanged(mTargetRadius);
+        }
+    }
+
     public final void setup(float maxRadius, float density) {
         if (maxRadius >= 0) {
             mHasMaxRadius = true;
             mTargetRadius = maxRadius;
         } else {
-            final float halfWidth = mBounds.width() / 2.0f;
-            final float halfHeight = mBounds.height() / 2.0f;
-            mTargetRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
+            mTargetRadius = getTargetRadius(mBounds);
         }
 
         mDensity = density;
@@ -72,6 +77,12 @@
         onTargetRadiusChanged(mTargetRadius);
     }
 
+    private static float getTargetRadius(Rect bounds) {
+        final float halfWidth = bounds.width() / 2.0f;
+        final float halfHeight = bounds.height() / 2.0f;
+        return (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
+    }
+
     /**
      * Starts a ripple enter animation.
      *
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index efc171c..f7e8ed0 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -31,7 +31,6 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.ColorFilter;
 import android.graphics.Matrix;
 import android.graphics.Outline;
 import android.graphics.Paint;
@@ -294,6 +293,14 @@
             onHotspotBoundsChanged();
         }
 
+        if (mBackground != null) {
+            mBackground.onBoundsChange();
+        }
+
+        if (mRipple != null) {
+            mRipple.onBoundsChange();
+        }
+
         invalidateSelf();
     }
 
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index b15caeb..5130e6c 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1132,6 +1132,24 @@
     // chars. Interpreted in conjunction with the locale field.
     char localeVariant[8];
 
+    enum {
+        // screenLayout2 bits for round/notround.
+        MASK_SCREENROUND = 0x03,
+        SCREENROUND_ANY = ACONFIGURATION_SCREENROUND_ANY,
+        SCREENROUND_NO = ACONFIGURATION_SCREENROUND_NO,
+        SCREENROUND_YES = ACONFIGURATION_SCREENROUND_YES,
+    };
+
+    // An extension of screenConfig.
+    union {
+        struct {
+            uint8_t screenLayout2;      // Contains round/notround qualifier.
+            uint8_t screenConfigPad1;   // Reserved padding.
+            uint16_t screenConfigPad2;  // Reserved padding.
+        };
+        uint32_t screenConfig2;
+    };
+
     void copyFromDeviceNoSwap(const ResTable_config& o);
     
     void copyFromDtoH(const ResTable_config& o);
@@ -1160,6 +1178,7 @@
         CONFIG_SCREEN_LAYOUT = ACONFIGURATION_SCREEN_LAYOUT,
         CONFIG_UI_MODE = ACONFIGURATION_UI_MODE,
         CONFIG_LAYOUTDIR = ACONFIGURATION_LAYOUTDIR,
+        CONFIG_SCREEN_ROUND = ACONFIGURATION_SCREEN_ROUND,
     };
     
     // Compare two configuration, returning CONFIG_* flags set for each value
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 2ae7b08..a95db9f 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1894,6 +1894,8 @@
     if (diff != 0) return diff;
     diff = (int32_t)(screenLayout - o.screenLayout);
     if (diff != 0) return diff;
+    diff = (int32_t)(screenLayout2 - o.screenLayout2);
+    if (diff != 0) return diff;
     diff = (int32_t)(uiMode - o.uiMode);
     if (diff != 0) return diff;
     diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
@@ -1951,6 +1953,9 @@
     if (screenLayout != o.screenLayout) {
         return screenLayout < o.screenLayout ? -1 : 1;
     }
+    if (screenLayout2 != o.screenLayout2) {
+        return screenLayout2 < o.screenLayout2 ? -1 : 1;
+    }
     if (uiMode != o.uiMode) {
         return uiMode < o.uiMode ? -1 : 1;
     }
@@ -1975,6 +1980,7 @@
     if (version != o.version) diffs |= CONFIG_VERSION;
     if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) diffs |= CONFIG_LAYOUTDIR;
     if ((screenLayout & ~MASK_LAYOUTDIR) != (o.screenLayout & ~MASK_LAYOUTDIR)) diffs |= CONFIG_SCREEN_LAYOUT;
+    if ((screenLayout2 & MASK_SCREENROUND) != (o.screenLayout2 & MASK_SCREENROUND)) diffs |= CONFIG_SCREEN_ROUND;
     if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
     if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
     if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
@@ -2080,6 +2086,13 @@
         }
     }
 
+    if (screenLayout2 || o.screenLayout2) {
+        if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0) {
+            if (!(screenLayout2 & MASK_SCREENROUND)) return false;
+            if (!(o.screenLayout2 & MASK_SCREENROUND)) return true;
+        }
+    }
+
     if (orientation != o.orientation) {
         if (!orientation) return false;
         if (!o.orientation) return true;
@@ -2267,6 +2280,13 @@
             }
         }
 
+        if (screenLayout2 || o.screenLayout2) {
+            if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0 &&
+                    (requested->screenLayout2 & MASK_SCREENROUND)) {
+                return screenLayout2 & MASK_SCREENROUND;
+            }
+        }
+
         if ((orientation != o.orientation) && requested->orientation) {
             return (orientation);
         }
@@ -2480,6 +2500,15 @@
             return false;
         }
     }
+
+    if (screenConfig2 != 0) {
+        const int screenRound = screenLayout2 & MASK_SCREENROUND;
+        const int setScreenRound = settings.screenLayout2 & MASK_SCREENROUND;
+        if (screenRound != 0 && screenRound != setScreenRound) {
+            return false;
+        }
+    }
+
     if (screenSizeDp != 0) {
         if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
             if (kDebugTableSuperNoisy) {
@@ -2770,6 +2799,20 @@
                 break;
         }
     }
+    if ((screenLayout2&MASK_SCREENROUND) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (screenLayout2&MASK_SCREENROUND) {
+            case SCREENROUND_NO:
+                res.append("notround");
+                break;
+            case SCREENROUND_YES:
+                res.append("round");
+                break;
+            default:
+                res.appendFormat("screenRound=%d", dtohs(screenLayout2&MASK_SCREENROUND));
+                break;
+        }
+    }
     if (orientation != ORIENTATION_ANY) {
         if (res.size() > 0) res.append("-");
         switch (orientation) {
diff --git a/libs/androidfw/tests/Config_test.cpp b/libs/androidfw/tests/Config_test.cpp
index ef30df4..738947a 100644
--- a/libs/androidfw/tests/Config_test.cpp
+++ b/libs/androidfw/tests/Config_test.cpp
@@ -100,4 +100,82 @@
     ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
 }
 
+TEST(ConfigTest, shouldMatchRoundQualifier) {
+    ResTable_config deviceConfig;
+    memset(&deviceConfig, 0, sizeof(deviceConfig));
+
+    ResTable_config roundConfig;
+    memset(&roundConfig, 0, sizeof(roundConfig));
+    roundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
+
+    EXPECT_FALSE(roundConfig.match(deviceConfig));
+
+    deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
+
+    EXPECT_TRUE(roundConfig.match(deviceConfig));
+
+    deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_NO;
+
+    EXPECT_FALSE(roundConfig.match(deviceConfig));
+
+    ResTable_config notRoundConfig;
+    memset(&notRoundConfig, 0, sizeof(notRoundConfig));
+    notRoundConfig.screenLayout2 = ResTable_config::SCREENROUND_NO;
+
+    EXPECT_TRUE(notRoundConfig.match(deviceConfig));
+}
+
+TEST(ConfigTest, RoundQualifierShouldHaveStableSortOrder) {
+    ResTable_config defaultConfig;
+    memset(&defaultConfig, 0, sizeof(defaultConfig));
+
+    ResTable_config longConfig = defaultConfig;
+    longConfig.screenLayout = ResTable_config::SCREENLONG_YES;
+
+    ResTable_config longRoundConfig = longConfig;
+    longRoundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
+
+    ResTable_config longRoundPortConfig = longConfig;
+    longRoundPortConfig.orientation = ResTable_config::ORIENTATION_PORT;
+
+    EXPECT_TRUE(longConfig.compare(longRoundConfig) < 0);
+    EXPECT_TRUE(longConfig.compareLogical(longRoundConfig) < 0);
+    EXPECT_TRUE(longRoundConfig.compare(longConfig) > 0);
+    EXPECT_TRUE(longRoundConfig.compareLogical(longConfig) > 0);
+
+    EXPECT_TRUE(longRoundConfig.compare(longRoundPortConfig) < 0);
+    EXPECT_TRUE(longRoundConfig.compareLogical(longRoundPortConfig) < 0);
+    EXPECT_TRUE(longRoundPortConfig.compare(longRoundConfig) > 0);
+    EXPECT_TRUE(longRoundPortConfig.compareLogical(longRoundConfig) > 0);
+}
+
+TEST(ConfigTest, ScreenShapeHasCorrectDiff) {
+    ResTable_config defaultConfig;
+    memset(&defaultConfig, 0, sizeof(defaultConfig));
+
+    ResTable_config roundConfig = defaultConfig;
+    roundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
+
+    EXPECT_EQ(defaultConfig.diff(roundConfig), ResTable_config::CONFIG_SCREEN_ROUND);
+}
+
+TEST(ConfigTest, RoundIsMoreSpecific) {
+    ResTable_config deviceConfig;
+    memset(&deviceConfig, 0, sizeof(deviceConfig));
+    deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
+    deviceConfig.screenLayout = ResTable_config::SCREENLONG_YES;
+
+    ResTable_config targetConfigA;
+    memset(&targetConfigA, 0, sizeof(targetConfigA));
+
+    ResTable_config targetConfigB = targetConfigA;
+    targetConfigB.screenLayout = ResTable_config::SCREENLONG_YES;
+
+    ResTable_config targetConfigC = targetConfigB;
+    targetConfigC.screenLayout2 = ResTable_config::SCREENROUND_YES;
+
+    EXPECT_TRUE(targetConfigB.isBetterThan(targetConfigA, &deviceConfig));
+    EXPECT_TRUE(targetConfigC.isBetterThan(targetConfigB, &deviceConfig));
+}
+
 }  // namespace android.
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index f893fdd..d21762b 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -98,6 +98,7 @@
     /** Maximum value for sample rate */
     private static final int SAMPLE_RATE_HZ_MAX = 192000;
 
+    // FCC_8
     /** Maximum value for AudioTrack channel count */
     private static final int CHANNEL_COUNT_MAX = 8;
 
@@ -191,13 +192,20 @@
 
     /**
      * The write mode indicating the write operation will block until all data has been written,
-     * to be used in {@link #write(ByteBuffer, int, int)}
+     * to be used as the actual value of the writeMode parameter in
+     * {@link #write(byte[], int, int, int)}, {@link #write(short[], int, int, int)},
+     * {@link #write(float[], int, int, int)}, {@link #write(ByteBuffer, int, int)}, and
+     * {@link #write(ByteBuffer, int, int, long)}.
      */
     public final static int WRITE_BLOCKING = 0;
+
     /**
      * The write mode indicating the write operation will return immediately after
-     * queuing as much audio data for playback as possible without blocking, to be used in
-     * {@link #write(ByteBuffer, int, int)}.
+     * queuing as much audio data for playback as possible without blocking,
+     * to be used as the actual value of the writeMode parameter in
+     * {@link #write(ByteBuffer, int, int)}, {@link #write(short[], int, int, int)},
+     * {@link #write(float[], int, int, int)}, {@link #write(ByteBuffer, int, int)}, and
+     * {@link #write(ByteBuffer, int, int, long)}.
      */
     public final static int WRITE_NON_BLOCKING = 1;
 
@@ -206,14 +214,16 @@
     //--------------------
     /**
      * Indicates the state of the AudioTrack instance.
+     * One of STATE_UNINITIALIZED, STATE_INITIALIZED, or STATE_NO_STATIC_DATA.
      */
     private int mState = STATE_UNINITIALIZED;
     /**
      * Indicates the play state of the AudioTrack instance.
+     * One of PLAYSTATE_STOPPED, PLAYSTATE_PAUSED, or PLAYSTATE_PLAYING.
      */
     private int mPlayState = PLAYSTATE_STOPPED;
     /**
-     * Lock to make sure mPlayState updates are reflecting the actual state of the object.
+     * Lock to ensure mPlayState updates reflect the actual state of the object.
      */
     private final Object mPlayStateLock = new Object();
     /**
@@ -234,9 +244,9 @@
     /**
      * The audio data source sampling rate in Hz.
      */
-    private int mSampleRate; // initialized by all constructors
+    private int mSampleRate; // initialized by all constructors via audioParamCheck()
     /**
-     * The number of audio output channels (1 is mono, 2 is stereo).
+     * The number of audio output channels (1 is mono, 2 is stereo, etc.).
      */
     private int mChannelCount = 1;
     /**
@@ -255,7 +265,7 @@
 
     private final AudioAttributes mAttributes;
     /**
-     * The way audio is consumed by the audio sink, streaming or static.
+     * The way audio is consumed by the audio sink, one of MODE_STATIC or MODE_STREAM.
      */
     private int mDataLoadMode = MODE_STREAM;
     /**
@@ -265,7 +275,7 @@
      */
     private int mChannelConfiguration = AudioFormat.CHANNEL_OUT_MONO;
     /**
-     * The current audio channel index configuration (if specified).
+     * The channel index mask if specified, otherwise 0.
      */
     private int mChannelIndexMask = 0;
     /**
@@ -274,7 +284,7 @@
      * @see AudioFormat#ENCODING_PCM_16BIT
      * @see AudioFormat#ENCODING_PCM_FLOAT
      */
-    private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
+    private int mAudioFormat;   // initialized by all constructors via audioParamCheck()
     /**
      * Audio session ID
      */
@@ -475,7 +485,7 @@
         IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
         mAppOps = IAppOpsService.Stub.asInterface(b);
 
-        mAttributes = (new AudioAttributes.Builder(attributes).build());
+        mAttributes = new AudioAttributes.Builder(attributes).build();
 
         if (sessionId < 0) {
             throw new IllegalArgumentException("Invalid audio session ID: "+sessionId);
@@ -683,7 +693,8 @@
         }
     }
 
-    // mask of all the channels supported by this implementation
+    // mask of all the positional channels supported, however the allowed combinations
+    // are further restricted by the matching left/right rule and CHANNEL_COUNT_MAX
     private static final int SUPPORTED_OUT_CHANNELS =
             AudioFormat.CHANNEL_OUT_FRONT_LEFT |
             AudioFormat.CHANNEL_OUT_FRONT_RIGHT |
@@ -834,8 +845,7 @@
         //     To update when supporting compressed formats
         int frameSizeInBytes;
         if (AudioFormat.isEncodingLinearPcm(mAudioFormat)) {
-            frameSizeInBytes = mChannelCount
-                    * (AudioFormat.getBytesPerSample(mAudioFormat));
+            frameSizeInBytes = mChannelCount * AudioFormat.getBytesPerSample(mAudioFormat);
         } else {
             frameSizeInBytes = 1;
         }
@@ -941,7 +951,7 @@
      * <p> For example, refer to {@link AudioFormat#CHANNEL_OUT_MONO},
      * {@link AudioFormat#CHANNEL_OUT_STEREO}, {@link AudioFormat#CHANNEL_OUT_5POINT1}.
      * This method may return {@link AudioFormat#CHANNEL_INVALID} if
-     * a channel index mask is used. Consider
+     * a channel index mask was used. Consider
      * {@link #getFormat()} instead, to obtain an {@link AudioFormat},
      * which contains both the channel position mask and the channel index mask.
      */
@@ -978,9 +988,9 @@
      * Returns the state of the AudioTrack instance. This is useful after the
      * AudioTrack instance has been created to check if it was initialized
      * properly. This ensures that the appropriate resources have been acquired.
+     * @see #STATE_UNINITIALIZED
      * @see #STATE_INITIALIZED
      * @see #STATE_NO_STATIC_DATA
-     * @see #STATE_UNINITIALIZED
      */
     public int getState() {
         return mState;
@@ -1455,14 +1465,27 @@
     //--------------------
     /**
      * Starts playing an AudioTrack.
+     * <p>
      * If track's creation mode is {@link #MODE_STATIC}, you must have called one of
-     * the {@link #write(byte[], int, int)}, {@link #write(short[], int, int)},
-     * or {@link #write(float[], int, int, int)} methods.
-     * If the mode is {@link #MODE_STREAM}, you can optionally prime the
-     * output buffer by writing up to bufferSizeInBytes (from constructor) before starting.
-     * This priming will avoid an immediate underrun, but is not required.
+     * the write methods ({@link #write(byte[], int, int)}, {@link #write(byte[], int, int, int)},
+     * {@link #write(short[], int, int)}, {@link #write(short[], int, int, int)},
+     * {@link #write(float[], int, int, int)}, or {@link #write(ByteBuffer, int, int)}) prior to
+     * play().
+     * <p>
+     * If the mode is {@link #MODE_STREAM}, you can optionally prime the data path prior to
+     * calling play(), by writing up to <code>bufferSizeInBytes</code> (from constructor).
+     * If you don’t call write() first, or if you call write() but with an insufficient amount of
+     * data, then the track will be in underrun state at play().  In this case,
+     * playback will not actually start playing until the data path is filled to a
+     * device-specific minimum level.  This requirement for the path to be filled
+     * to a minimum level is also true when resuming audio playback after calling stop().
+     * Similarly the buffer will need to be filled up again after
+     * the track underruns due to failure to call write() in a timely manner with sufficient data.
+     * For portability, an application should prime the data path to the maximum allowed
+     * by writing data until the write() method returns a short transfer count.
+     * This allows play() to start immediately, and reduces the chance of underrun.
      *
-     * @throws IllegalStateException
+     * @throws IllegalStateException if the track isn't properly initialized
      */
     public void play()
     throws IllegalStateException {
@@ -1567,21 +1590,30 @@
      * or copies audio data for later playback (static buffer mode).
      * The format specified in the AudioTrack constructor should be
      * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
-     * In streaming mode, will block until all data has been written to the audio sink.
+     * <p>
+     * In streaming mode, the write will normally block until all the data has been enqueued for
+     * playback, and will return a full transfer count.  However, if the track is stopped or paused
+     * on entry, or another thread interrupts the write by calling stop or pause, or an I/O error
+     * occurs during the write, then the write may return a short transfer count.
+     * <p>
      * In static buffer mode, copies the data to the buffer starting at offset 0.
-     * Note that the actual playback of this data might occur after this function
-     * returns. This function is thread safe with respect to {@link #stop} calls,
-     * in which case all of the specified data might not be written to the audio sink.
+     * Note that the actual playback of this data might occur after this function returns.
      *
      * @param audioData the array that holds the data to play.
      * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
      *    starts.
      * @param sizeInBytes the number of bytes to read in audioData after the offset.
-     * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     * @return zero or the positive number of bytes that were written, or
+     *    {@link #ERROR_INVALID_OPERATION}
+     *    if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
      *    the parameters don't resolve to valid data and indexes, or
      *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
      *    needs to be recreated.
+     *    The dead object error code is not returned if some data was successfully transferred.
+     *    In this case, the error is returned at the next write().
+     *
+     * This is equivalent to {@link #write(byte[], int, int, int)} with <code>writeMode</code>
+     * set to  {@link #WRITE_BLOCKING}.
      */
     public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
         return write(audioData, offsetInBytes, sizeInBytes, WRITE_BLOCKING);
@@ -1592,11 +1624,17 @@
      * or copies audio data for later playback (static buffer mode).
      * The format specified in the AudioTrack constructor should be
      * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
-     * In streaming mode, will block until all data has been written to the audio sink.
-     * In static buffer mode, copies the data to the buffer starting at offset 0.
-     * Note that the actual playback of this data might occur after this function
-     * returns. This function is thread safe with respect to {@link #stop} calls,
-     * in which case all of the specified data might not be written to the audio sink.
+     * <p>
+     * In streaming mode, the blocking behavior depends on the write mode.  If the write mode is
+     * {@link #WRITE_BLOCKING}, the write will normally block until all the data has been enqueued
+     * for playback, and will return a full transfer count.  However, if the write mode is
+     * {@link #WRITE_NON_BLOCKING}, or the track is stopped or paused on entry, or another thread
+     * interrupts the write by calling stop or pause, or an I/O error
+     * occurs during the write, then the write may return a short transfer count.
+     * <p>
+     * In static buffer mode, copies the data to the buffer starting at offset 0,
+     * and the write mode is ignored.
+     * Note that the actual playback of this data might occur after this function returns.
      *
      * @param audioData the array that holds the data to play.
      * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
@@ -1608,11 +1646,14 @@
      *         to the audio sink.
      *     <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
-     * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     * @return zero or the positive number of bytes that were written, or
+     *    {@link #ERROR_INVALID_OPERATION}
+     *    if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
      *    the parameters don't resolve to valid data and indexes, or
      *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
      *    needs to be recreated.
+     *    The dead object error code is not returned if some data was successfully transferred.
+     *    In this case, the error is returned at the next write().
      */
     public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
             @WriteMode int writeMode) {
@@ -1650,21 +1691,30 @@
      * or copies audio data for later playback (static buffer mode).
      * The format specified in the AudioTrack constructor should be
      * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
-     * In streaming mode, will block until all data has been written to the audio sink.
+     * <p>
+     * In streaming mode, the write will normally block until all the data has been enqueued for
+     * playback, and will return a full transfer count.  However, if the track is stopped or paused
+     * on entry, or another thread interrupts the write by calling stop or pause, or an I/O error
+     * occurs during the write, then the write may return a short transfer count.
+     * <p>
      * In static buffer mode, copies the data to the buffer starting at offset 0.
-     * Note that the actual playback of this data might occur after this function
-     * returns. This function is thread safe with respect to {@link #stop} calls,
-     * in which case all of the specified data might not be written to the audio sink.
+     * Note that the actual playback of this data might occur after this function returns.
      *
      * @param audioData the array that holds the data to play.
      * @param offsetInShorts the offset expressed in shorts in audioData where the data to play
      *     starts.
      * @param sizeInShorts the number of shorts to read in audioData after the offset.
-     * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     * @return zero or the positive number of shorts that were written, or
+     *    {@link #ERROR_INVALID_OPERATION}
+     *    if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
      *    the parameters don't resolve to valid data and indexes, or
      *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
      *    needs to be recreated.
+     *    The dead object error code is not returned if some data was successfully transferred.
+     *    In this case, the error is returned at the next write().
+     *
+     * This is equivalent to {@link #write(short[], int, int, int)} with <code>writeMode</code>
+     * set to  {@link #WRITE_BLOCKING}.
      */
     public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) {
         return write(audioData, offsetInShorts, sizeInShorts, WRITE_BLOCKING);
@@ -1675,11 +1725,16 @@
      * or copies audio data for later playback (static buffer mode).
      * The format specified in the AudioTrack constructor should be
      * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
-     * In streaming mode, will block until all data has been written to the audio sink.
+     * <p>
+     * In streaming mode, the blocking behavior depends on the write mode.  If the write mode is
+     * {@link #WRITE_BLOCKING}, the write will normally block until all the data has been enqueued
+     * for playback, and will return a full transfer count.  However, if the write mode is
+     * {@link #WRITE_NON_BLOCKING}, or the track is stopped or paused on entry, or another thread
+     * interrupts the write by calling stop or pause, or an I/O error
+     * occurs during the write, then the write may return a short transfer count.
+     * <p>
      * In static buffer mode, copies the data to the buffer starting at offset 0.
-     * Note that the actual playback of this data might occur after this function
-     * returns. This function is thread safe with respect to {@link #stop} calls,
-     * in which case all of the specified data might not be written to the audio sink.
+     * Note that the actual playback of this data might occur after this function returns.
      *
      * @param audioData the array that holds the data to play.
      * @param offsetInShorts the offset expressed in shorts in audioData where the data to play
@@ -1691,11 +1746,14 @@
      *         to the audio sink.
      *     <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
-     * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     * @return zero or the positive number of shorts that were written, or
+     *    {@link #ERROR_INVALID_OPERATION}
+     *    if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
      *    the parameters don't resolve to valid data and indexes, or
      *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
      *    needs to be recreated.
+     *    The dead object error code is not returned if some data was successfully transferred.
+     *    In this case, the error is returned at the next write().
      */
     public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
             @WriteMode int writeMode) {
@@ -1733,14 +1791,18 @@
      * or copies audio data for later playback (static buffer mode).
      * The format specified in the AudioTrack constructor should be
      * {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array.
+     * <p>
+     * In streaming mode, the blocking behavior depends on the write mode.  If the write mode is
+     * {@link #WRITE_BLOCKING}, the write will normally block until all the data has been enqueued
+     * for playback, and will return a full transfer count.  However, if the write mode is
+     * {@link #WRITE_NON_BLOCKING}, or the track is stopped or paused on entry, or another thread
+     * interrupts the write by calling stop or pause, or an I/O error
+     * occurs during the write, then the write may return a short transfer count.
+     * <p>
      * In static buffer mode, copies the data to the buffer starting at offset 0,
      * and the write mode is ignored.
-     * In streaming mode, the blocking behavior will depend on the write mode.
-     * <p>
-     * Note that the actual playback of this data might occur after this function
-     * returns. This function is thread safe with respect to {@link #stop} calls,
-     * in which case all of the specified data might not be written to the audio sink.
-     * <p>
+     * Note that the actual playback of this data might occur after this function returns.
+     *
      * @param audioData the array that holds the data to play.
      *     The implementation does not clip for sample values within the nominal range
      *     [-1.0f, 1.0f], provided that all gains in the audio pipeline are
@@ -1760,11 +1822,14 @@
      *         to the audio sink.
      *     <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
-     * @return the number of floats that were written, or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     * @return zero or the positive number of floats that were written, or
+     *    {@link #ERROR_INVALID_OPERATION}
+     *    if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
      *    the parameters don't resolve to valid data and indexes, or
      *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
      *    needs to be recreated.
+     *    The dead object error code is not returned if some data was successfully transferred.
+     *    In this case, the error is returned at the next write().
      */
     public int write(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
             @WriteMode int writeMode) {
@@ -1808,9 +1873,19 @@
     /**
      * Writes the audio data to the audio sink for playback (streaming mode),
      * or copies audio data for later playback (static buffer mode).
-     * In static buffer mode, copies the data to the buffer starting at its 0 offset, and the write
-     * mode is ignored.
-     * In streaming mode, the blocking behavior will depend on the write mode.
+     * The audioData in ByteBuffer should match the format specified in the AudioTrack constructor.
+     * <p>
+     * In streaming mode, the blocking behavior depends on the write mode.  If the write mode is
+     * {@link #WRITE_BLOCKING}, the write will normally block until all the data has been enqueued
+     * for playback, and will return a full transfer count.  However, if the write mode is
+     * {@link #WRITE_NON_BLOCKING}, or the track is stopped or paused on entry, or another thread
+     * interrupts the write by calling stop or pause, or an I/O error
+     * occurs during the write, then the write may return a short transfer count.
+     * <p>
+     * In static buffer mode, copies the data to the buffer starting at offset 0,
+     * and the write mode is ignored.
+     * Note that the actual playback of this data might occur after this function returns.
+     *
      * @param audioData the buffer that holds the data to play, starting at the position reported
      *     by <code>audioData.position()</code>.
      *     <BR>Note that upon return, the buffer position (<code>audioData.position()</code>) will
@@ -1824,10 +1899,12 @@
      *         to the audio sink.
      *     <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
-     * @return 0 or a positive number of bytes that were written, or
+     * @return zero or the positive number of bytes that were written, or
      *     {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}, or
      *     {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
      *     needs to be recreated.
+     *     The dead object error code is not returned if some data was successfully transferred.
+     *     In this case, the error is returned at the next write().
      */
     public int write(@NonNull ByteBuffer audioData, int sizeInBytes,
             @WriteMode int writeMode) {
@@ -1874,8 +1951,8 @@
     }
 
     /**
-     * Writes the audio data to the audio sink for playback (streaming mode) on a HW_AV_SYNC track.
-     * In streaming mode, the blocking behavior will depend on the write mode.
+     * Writes the audio data to the audio sink for playback in streaming mode on a HW_AV_SYNC track.
+     * The blocking behavior will depend on the write mode.
      * @param audioData the buffer that holds the data to play, starting at the position reported
      *     by <code>audioData.position()</code>.
      *     <BR>Note that upon return, the buffer position (<code>audioData.position()</code>) will
@@ -1889,10 +1966,12 @@
      *     <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
      * @param timestamp The timestamp of the first decodable audio frame in the provided audioData.
-     * @return 0 or a positive number of bytes that were written, or
+     * @return zero or a positive number of bytes that were written, or
      *     {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}, or
      *     {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
      *     needs to be recreated.
+     *     The dead object error code is not returned if some data was successfully transferred.
+     *     In this case, the error is returned at the next write().
      */
     public int write(ByteBuffer audioData, int sizeInBytes,
             @WriteMode int writeMode, long timestamp) {
diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp
index 74cf80e..77237ae 100644
--- a/native/android/configuration.cpp
+++ b/native/android/configuration.cpp
@@ -101,6 +101,10 @@
             >> ResTable_config::SHIFT_SCREENLONG;
 }
 
+int32_t AConfiguration_getScreenRound(AConfiguration* config) {
+    return (config->screenLayout2&ResTable_config::MASK_SCREENROUND);
+}
+
 int32_t AConfiguration_getUiModeType(AConfiguration* config) {
     return config->uiMode&ResTable_config::MASK_UI_MODE_TYPE;
 }
@@ -192,6 +196,11 @@
             | ((screenLong<<ResTable_config::SHIFT_SCREENLONG)&ResTable_config::MASK_SCREENLONG);
 }
 
+void AConfiguration_setScreenRound(AConfiguration* config, int32_t screenRound) {
+    config->screenLayout2 = (config->screenLayout2&~ResTable_config::MASK_SCREENROUND)
+            | (screenRound&ResTable_config::MASK_SCREENROUND);
+}
+
 void AConfiguration_setUiModeType(AConfiguration* config, int32_t uiModeType) {
     config->uiMode = (config->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
             | (uiModeType&ResTable_config::MASK_UI_MODE_TYPE);
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 1019e6c..c7b7e6a 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -146,6 +146,7 @@
     private void done(Result result) {
         if (mNetworkCallback != null) {
             mCm.unregisterNetworkCallback(mNetworkCallback);
+            mNetworkCallback = null;
         }
         switch (result) {
             case DISMISSED:
@@ -191,6 +192,16 @@
         return super.onOptionsItemSelected(item);
     }
 
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+
+        if (mNetworkCallback != null) {
+            mCm.unregisterNetworkCallback(mNetworkCallback);
+            mNetworkCallback = null;
+        }
+    }
+
     private void testForCaptivePortal() {
         new Thread(new Runnable() {
             public void run() {
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 1cabcdfc..e03f449 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -16,6 +16,7 @@
 
 package com.android.keyguard;
 
+import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
@@ -42,7 +43,7 @@
             .setPackage("com.android.phone")
             .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                     | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-                    | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
     KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
 
@@ -127,6 +128,7 @@
             KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(
                     true /* bypassHandler */);
             getContext().startActivityAsUser(INTENT_EMERGENCY_DIAL,
+                    ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(),
                     new UserHandle(KeyguardUpdateMonitor.getCurrentUser()));
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 2d1fab0..c702673 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -621,10 +621,11 @@
                 mHeaderBar.draw(c);
                 c.setBitmap(null);
             }
+            Bitmap thumbnailImmutable = thumbnail.createAshmemBitmap();
 
             mStartAnimationTriggered = false;
             return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
-                    thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
+                    thumbnailImmutable, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
                     toTaskRect.height(), mHandler, this);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 1377975..b3e6221 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -490,6 +490,7 @@
                 // Notify the system to skip the thumbnail layer by using an ALPHA_8 bitmap
                 b = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
             }
+            Bitmap bImmut = b.createAshmemBitmap();
             ActivityOptions.OnAnimationStartedListener animStartedListener = null;
             if (lockToTask) {
                 animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
@@ -515,7 +516,7 @@
                         sourceView.getHandler(), animStartedListener);
             } else {
                 opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
-                        b, offsetX, offsetY, transform.rect.width(), transform.rect.height(),
+                        bImmut, offsetX, offsetY, transform.rect.width(), transform.rect.height(),
                         sourceView.getHandler(), animStartedListener);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 17e2cb5..3feec9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -59,6 +59,12 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int ownMaxHeight = mMaxViewHeight;
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
+        if (hasFixedHeight) {
+            // We have a height set in our layout, so we want to be at most as big as given
+            ownMaxHeight = Math.min(MeasureSpec.getSize(heightMeasureSpec), ownMaxHeight);
+        }
         int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
         int maxChildHeight = 0;
         int childCount = getChildCount();
@@ -85,7 +91,7 @@
                 mMatchParentViews.add(child);
             }
         }
-        int ownHeight = Math.min(ownMaxHeight, maxChildHeight);
+        int ownHeight = hasFixedHeight ? ownMaxHeight : Math.min(ownMaxHeight, maxChildHeight);
         newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
         for (View child : mMatchParentViews) {
             child.measure(getChildMeasureSpec(
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index ea8b2ec..48e0582 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -21,6 +21,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.IConnectivityManager;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.text.Html;
 import android.text.Html.ImageGetter;
 import android.util.Log;
@@ -50,7 +51,7 @@
             mService = IConnectivityManager.Stub.asInterface(
                     ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
 
-            if (mService.prepareVpn(mPackage, null)) {
+            if (mService.prepareVpn(mPackage, null, UserHandle.myUserId())) {
                 setResult(RESULT_OK);
                 finish();
                 return;
@@ -94,10 +95,10 @@
     @Override
     public void onClick(DialogInterface dialog, int which) {
         try {
-            if (mService.prepareVpn(null, mPackage)) {
+            if (mService.prepareVpn(null, mPackage, UserHandle.myUserId())) {
                 // Authorize this app to initiate VPN connections in the future without user
                 // intervention.
-                mService.setVpnPackageAuthorization(true);
+                mService.setVpnPackageAuthorization(mPackage, UserHandle.myUserId(), true);
                 setResult(RESULT_OK);
             }
         } catch (Exception e) {
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index cc8500a..76b2346 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -23,6 +23,7 @@
 import android.os.Message;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.View;
 import android.widget.TextView;
@@ -63,7 +64,7 @@
             mService = IConnectivityManager.Stub.asInterface(
                     ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
 
-            mConfig = mService.getVpnConfig();
+            mConfig = mService.getVpnConfig(UserHandle.myUserId());
 
             // mConfig can be null if we are a restricted user, in that case don't show this dialog
             if (mConfig == null) {
@@ -120,10 +121,11 @@
             if (which == DialogInterface.BUTTON_POSITIVE) {
                 mConfig.configureIntent.send();
             } else if (which == DialogInterface.BUTTON_NEUTRAL) {
+                final int myUserId = UserHandle.myUserId();
                 if (mConfig.legacy) {
-                    mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+                    mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, myUserId);
                 } else {
-                    mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
+                    mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN, myUserId);
                 }
             }
         } catch (Exception e) {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index f5d27f9..c46fa76 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.Manifest;
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothProfile;
@@ -909,16 +910,22 @@
             mCallbacks.finishBroadcast();
         }
     }
+
     public String getAddress() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
-                                                "Need BLUETOOTH permission");
+                "Need BLUETOOTH permission");
 
         if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
-            (!checkIfCallerIsForegroundUser())) {
+                (!checkIfCallerIsForegroundUser())) {
             Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
             return null;
         }
 
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.LOCAL_MAC_ADDRESS)
+                != PackageManager.PERMISSION_GRANTED) {
+            return BluetoothAdapter.DEFAULT_MAC_ADDRESS;
+        }
+
         synchronized(mConnection) {
             if (mBluetooth != null) {
                 try {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 02bffc4..1919c37 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1071,23 +1071,6 @@
         }
     }
 
-    private NetworkCapabilities getNetworkCapabilitiesAndValidation(NetworkAgentInfo nai) {
-        if (nai != null) {
-            synchronized (nai) {
-                if (nai.created) {
-                    NetworkCapabilities nc = new NetworkCapabilities(nai.networkCapabilities);
-                    if (nai.lastValidated) {
-                        nc.addCapability(NET_CAPABILITY_VALIDATED);
-                    } else {
-                        nc.removeCapability(NET_CAPABILITY_VALIDATED);
-                    }
-                    return nc;
-                }
-            }
-        }
-        return null;
-    }
-
     @Override
     public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
         // The basic principle is: if an app's traffic could possibly go over a
@@ -1109,7 +1092,7 @@
         HashMap<Network, NetworkCapabilities> result = new HashMap<Network, NetworkCapabilities>();
 
         NetworkAgentInfo nai = getDefaultNetwork();
-        NetworkCapabilities nc = getNetworkCapabilitiesAndValidation(getDefaultNetwork());
+        NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
         if (nc != null) {
             result.put(nai.network, nc);
         }
@@ -1122,9 +1105,9 @@
                     if (networks != null) {
                         for (Network network : networks) {
                             nai = getNetworkAgentInfoForNetwork(network);
-                            nc = getNetworkCapabilitiesAndValidation(nai);
+                            nc = getNetworkCapabilitiesInternal(nai);
                             if (nc != null) {
-                                result.put(nai.network, nc);
+                                result.put(network, nc);
                             }
                         }
                     }
@@ -1184,25 +1167,24 @@
         return null;
     }
 
-    @Override
-    public NetworkCapabilities getNetworkCapabilities(Network network) {
-        enforceAccessPermission();
-        NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+    private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
         if (nai != null) {
             synchronized (nai) {
-                NetworkCapabilities nc = new NetworkCapabilities(nai.networkCapabilities);
-                if (nai.lastValidated) {
-                    nc.addCapability(NET_CAPABILITY_VALIDATED);
-                } else {
-                    nc.removeCapability(NET_CAPABILITY_VALIDATED);
+                if (nai.networkCapabilities != null) {
+                    return new NetworkCapabilities(nai.networkCapabilities);
                 }
-                return nc;
             }
         }
         return null;
     }
 
     @Override
+    public NetworkCapabilities getNetworkCapabilities(Network network) {
+        enforceAccessPermission();
+        return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
+    }
+
+    @Override
     public NetworkState[] getAllNetworkState() {
         // Require internal since we're handing out IMSI details
         enforceConnectivityInternalPermission();
@@ -1410,6 +1392,22 @@
         }
     };
 
+    /**
+     * Require that the caller is either in the same user or has appropriate permission to interact
+     * across users.
+     *
+     * @param userId Target user for whatever operation the current IPC is supposed to perform.
+     */
+    private void enforceCrossUserPermission(int userId) {
+        if (userId == UserHandle.getCallingUserId()) {
+            // Not a cross-user call.
+            return;
+        }
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                "ConnectivityService");
+    }
+
     private void enforceInternetPermission() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.INTERNET,
@@ -1950,11 +1948,14 @@
                 }
                 case NetworkMonitor.EVENT_NETWORK_TESTED: {
                     NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
-                    if (isLiveNetworkAgent(nai, "EVENT_NETWORK_VALIDATED")) {
-                        boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+                    if (isLiveNetworkAgent(nai, "EVENT_NETWORK_TESTED")) {
+                        final boolean valid =
+                                (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+                        final boolean validationChanged = (valid != nai.lastValidated);
                         nai.lastValidated = valid;
                         if (valid) {
                             if (DBG) log("Validated " + nai.name());
+                            nai.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
                             if (!nai.everValidated) {
                                 nai.everValidated = true;
                                 rematchNetworkAndRequests(nai, NascentState.JUST_VALIDATED,
@@ -1962,6 +1963,8 @@
                                 // If score has changed, rebroadcast to NetworkFactories. b/17726566
                                 sendUpdatedScoreToFactories(nai);
                             }
+                        } else {
+                            nai.networkCapabilities.removeCapability(NET_CAPABILITY_VALIDATED);
                         }
                         updateInetCondition(nai);
                         // Let the NetworkAgent know the state of its network
@@ -1970,8 +1973,9 @@
                                 (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
                                 0, null);
 
-                        // TODO: trigger a NetworkCapabilities update so that the dialog can know
-                        // that the network is now validated and close itself.
+                        if (validationChanged) {
+                            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
+                        }
                     }
                     break;
                 }
@@ -2945,29 +2949,48 @@
 
     /**
      * Prepare for a VPN application.
-     * Permissions are checked in Vpn class.
+     * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
+     * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+     *
+     * @param oldPackage Package name of the application which currently controls VPN, which will
+     *                   be replaced. If there is no such application, this should should either be
+     *                   {@code null} or {@link VpnConfig.LEGACY_VPN}.
+     * @param newPackage Package name of the application which should gain control of VPN, or
+     *                   {@code null} to disable.
+     * @param userId User for whom to prepare the new VPN.
+     *
      * @hide
      */
     @Override
-    public boolean prepareVpn(String oldPackage, String newPackage) {
+    public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
+            int userId) {
+        enforceCrossUserPermission(userId);
         throwIfLockdownEnabled();
-        int user = UserHandle.getUserId(Binder.getCallingUid());
+
         synchronized(mVpns) {
-            return mVpns.get(user).prepare(oldPackage, newPackage);
+            return mVpns.get(userId).prepare(oldPackage, newPackage);
         }
     }
 
     /**
-     * Set whether the current VPN package has the ability to launch VPNs without
-     * user intervention. This method is used by system-privileged apps.
-     * Permissions are checked in Vpn class.
+     * Set whether the VPN package has the ability to launch VPNs without user intervention.
+     * This method is used by system-privileged apps.
+     * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
+     * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+     *
+     * @param packageName The package for which authorization state should change.
+     * @param userId User for whom {@code packageName} is installed.
+     * @param authorized {@code true} if this app should be able to start a VPN connection without
+     *                   explicit user approval, {@code false} if not.
+     *
      * @hide
      */
     @Override
-    public void setVpnPackageAuthorization(boolean authorized) {
-        int user = UserHandle.getUserId(Binder.getCallingUid());
+    public void setVpnPackageAuthorization(String packageName, int userId, boolean authorized) {
+        enforceCrossUserPermission(userId);
+
         synchronized(mVpns) {
-            mVpns.get(user).setPackageAuthorization(authorized);
+            mVpns.get(userId).setPackageAuthorization(packageName, authorized);
         }
     }
 
@@ -3069,16 +3092,16 @@
     }
 
     /**
-     * Returns the information of the ongoing VPN. This method is used by VpnDialogs and
-     * not available in ConnectivityManager.
+     * Returns the information of the ongoing VPN for {@code userId}. This method is used by
+     * VpnDialogs and not available in ConnectivityManager.
      * Permissions are checked in Vpn class.
      * @hide
      */
     @Override
-    public VpnConfig getVpnConfig() {
-        int user = UserHandle.getUserId(Binder.getCallingUid());
+    public VpnConfig getVpnConfig(int userId) {
+        enforceCrossUserPermission(userId);
         synchronized(mVpns) {
-            return mVpns.get(user).getVpnConfig();
+            return mVpns.get(userId).getVpnConfig();
         }
     }
 
@@ -3534,8 +3557,7 @@
     }
 
     private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities) {
-        if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
-                == false) {
+        if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) == false) {
             enforceConnectivityInternalPermission();
         } else {
             enforceChangePermission();
@@ -3562,8 +3584,7 @@
 
     private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) {
         // if UID is restricted, don't allow them to bring up metered APNs
-        if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)
-                == false) {
+        if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED) == false) {
             final int uidRules;
             final int uid = Binder.getCallingUid();
             synchronized(mRulesLock) {
@@ -3934,6 +3955,11 @@
             synchronized (networkAgent) {
                 networkAgent.networkCapabilities = networkCapabilities;
             }
+            if (networkAgent.lastValidated) {
+                networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
+                // There's no need to remove the capability if we think the network is unvalidated,
+                // because NetworkAgents don't set the validated capability.
+            }
             rematchAllNetworksAndRequests(networkAgent, networkAgent.getCurrentScore());
             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
@@ -4560,6 +4586,8 @@
     @Override
     public void factoryReset() {
         enforceConnectivityInternalPermission();
+        final int userId = UserHandle.getCallingUserId();
+
         // Turn airplane mode off
         setAirplaneMode(false);
 
@@ -4569,16 +4597,16 @@
         }
 
         // Turn VPN off
-        VpnConfig vpnConfig = getVpnConfig();
+        VpnConfig vpnConfig = getVpnConfig(userId);
         if (vpnConfig != null) {
             if (vpnConfig.legacy) {
-                prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+                prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId);
             } else {
-                // Prevent this app from initiating VPN connections in the future without
-                // user intervention.
-                setVpnPackageAuthorization(false);
+                // Prevent this app (packagename = vpnConfig.user) from initiating VPN connections
+                // in the future without user intervention.
+                setVpnPackageAuthorization(vpnConfig.user, userId, false);
 
-                prepareVpn(vpnConfig.user, VpnConfig.LEGACY_VPN);
+                prepareVpn(vpnConfig.user, VpnConfig.LEGACY_VPN, userId);
             }
         }
     }
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index ef9d0c3..4b65dec 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -72,7 +72,9 @@
 # when a notification action button has been clicked
 27521 notification_action_clicked (key|3),(action_index|1)
 # when a notification has been canceled
-27530 notification_canceled (key|3),(reason|1),(lifespan|1)
+27530 notification_canceled (key|3),(reason|1),(lifespan|1),(exposure|1)
+# replaces 27510 with a row per notification
+27531 notification_visibility (key|3),(visibile|1),(lifespan|1),(freshness|1)
 
 # ---------------------------
 # Watchdog.java
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a8ab667..2d74618 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6164,17 +6164,6 @@
         }
     }
 
-    @Override
-    public void systemBackupRestored() {
-        synchronized (this) {
-            if (mSystemReady) {
-                mTaskPersister.restoreTasksFromOtherDeviceLocked();
-            } else {
-                Slog.w(TAG, "System backup restored before system is ready");
-            }
-        }
-    }
-
     final void ensureBootCompleted() {
         boolean booting;
         boolean enableScreen;
@@ -11327,7 +11316,6 @@
 
             mRecentTasks.clear();
             mRecentTasks.addAll(mTaskPersister.restoreTasksLocked());
-            mTaskPersister.restoreTasksFromOtherDeviceLocked();
             mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
             mTaskPersister.startPersisting();
 
@@ -16191,18 +16179,12 @@
                                         removeUriPermissionsForPackageLocked(ssp, userId, true);
 
                                         removeTasksByPackageNameLocked(ssp, userId);
-                                        if (userId == UserHandle.USER_OWNER) {
-                                            mTaskPersister.removeFromPackageCache(ssp);
-                                        }
                                         mBatteryStatsService.notePackageUninstalled(ssp);
                                     }
                                 } else {
                                     cleanupDisabledPackageComponentsLocked(ssp, userId,
                                             intent.getStringArrayExtra(
                                                     Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
-                                    if (userId == UserHandle.USER_OWNER) {
-                                        mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp);
-                                    }
                                 }
                             }
                             break;
@@ -16217,9 +16199,6 @@
                                 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                         mCompatModePackages.handlePackageAddedLocked(ssp, replacing);
 
-                        if (userId == UserHandle.USER_OWNER) {
-                            mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp);
-                        }
                         try {
                             ApplicationInfo ai = AppGlobals.getPackageManager().
                                     getApplicationInfo(ssp, 0, 0);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index f3b18f5..ca1fd6a 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,8 +17,6 @@
 package com.android.server.am;
 
 import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.TaskPersister.DEBUG_PERSISTER;
-import static com.android.server.am.TaskPersister.DEBUG_RESTORER;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
 
 import android.app.ActivityManager.TaskDescription;
@@ -85,7 +83,7 @@
     private static final String ATTR_USERID = "user_id";
     private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle";
     private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid";
-    static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package";
+    private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package";
     private static final String ATTR_RESOLVEDTYPE = "resolved_type";
     private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
     static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
@@ -94,7 +92,7 @@
     final IApplicationToken.Stub appToken; // window manager token
     final ActivityInfo info; // all about me
     final ApplicationInfo appInfo; // information about activity's app
-    int launchedFromUid; // always the uid who started the activity.
+    final int launchedFromUid; // always the uid who started the activity.
     final String launchedFromPackage; // always the package who started the activity.
     final int userId;          // Which user is this running for?
     final Intent intent;    // the original intent that generated us
@@ -1178,8 +1176,8 @@
         }
     }
 
-    static ActivityRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
-            throws IOException, XmlPullParserException {
+    static ActivityRecord restoreFromXml(XmlPullParser in,
+            ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException {
         Intent intent = null;
         PersistableBundle persistentState = null;
         int launchedFromUid = 0;
@@ -1194,7 +1192,7 @@
         for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
             final String attrName = in.getAttributeName(attrNdx);
             final String attrValue = in.getAttributeValue(attrNdx);
-            if (DEBUG_PERSISTER || DEBUG_RESTORER) Slog.d(TaskPersister.TAG,
+            if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
                         "ActivityRecord: attribute name=" + attrName + " value=" + attrValue);
             if (ATTR_ID.equals(attrName)) {
                 createTime = Long.valueOf(attrValue);
@@ -1220,15 +1218,15 @@
                 (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
             if (event == XmlPullParser.START_TAG) {
                 final String name = in.getName();
-                if (DEBUG_PERSISTER || DEBUG_RESTORER)
+                if (TaskPersister.DEBUG)
                         Slog.d(TaskPersister.TAG, "ActivityRecord: START_TAG name=" + name);
                 if (TAG_INTENT.equals(name)) {
                     intent = Intent.restoreFromXml(in);
-                    if (DEBUG_PERSISTER || DEBUG_RESTORER)
+                    if (TaskPersister.DEBUG)
                             Slog.d(TaskPersister.TAG, "ActivityRecord: intent=" + intent);
                 } else if (TAG_PERSISTABLEBUNDLE.equals(name)) {
                     persistentState = PersistableBundle.restoreFromXml(in);
-                    if (DEBUG_PERSISTER || DEBUG_RESTORER) Slog.d(TaskPersister.TAG,
+                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
                             "ActivityRecord: persistentState=" + persistentState);
                 } else {
                     Slog.w(TAG, "restoreActivity: unexpected name=" + name);
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 318cd45..ef1559a 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -59,8 +59,7 @@
 
 public class TaskPersister {
     static final String TAG = "TaskPersister";
-    static final boolean DEBUG_PERSISTER = false;
-    static final boolean DEBUG_RESTORER = false;
+    static final boolean DEBUG = false;
 
     /** When not flushing don't write out files faster than this */
     private static final long INTER_WRITE_DELAY_MS = 500;
@@ -81,21 +80,10 @@
     private static final String IMAGES_DIRNAME = "recent_images";
     static final String IMAGE_EXTENSION = ".png";
 
-    // Directory where restored historical task XML/PNG files are placed.  This directory
-    // contains subdirs named after TASKS_DIRNAME and IMAGES_DIRNAME mirroring the
-    // ancestral device's dataset.  This needs to match the RECENTS_TASK_RESTORE_DIR
-    // value in RecentsBackupHelper.
-    private static final String RESTORED_TASKS_DIRNAME = "restored_" + TASKS_DIRNAME;
-
-    // Max time to wait for the application/package of a restored task to be installed
-    // before giving up.
-    private static final long MAX_INSTALL_WAIT_TIME = DateUtils.DAY_IN_MILLIS;
-
     private static final String TAG_TASK = "task";
 
     static File sImagesDir;
     static File sTasksDir;
-    static File sRestoredTasksDir;
 
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
@@ -129,23 +117,11 @@
 
     ArrayList<WriteQueueItem> mWriteQueue = new ArrayList<WriteQueueItem>();
 
-    // Map of tasks that were backed-up on a different device that can be restored on this device.
-    // Data organization: <packageNameOfAffiliateTask, listOfAffiliatedTasksChains>
-    private ArrayMap<String, List<List<OtherDeviceTask>>> mOtherDeviceTasksMap =
-                new ArrayMap<>(10);
-    // Local cache of package names to uid used when restoring a task from another device.
-    private ArrayMap<String, Integer> mPackageUidMap;
-
-    // The next time in milliseconds we will remove expired task from
-    // {@link #mOtherDeviceTasksMap} and disk. Set to {@link Long.MAX_VALUE} to never clean-up
-    // tasks.
-    private long mExpiredTasksCleanupTime = Long.MAX_VALUE;
-
     TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor,
             RecentTasks recentTasks) {
         sTasksDir = new File(systemDir, TASKS_DIRNAME);
         if (!sTasksDir.exists()) {
-            if (DEBUG_PERSISTER) Slog.d(TAG, "Creating tasks directory " + sTasksDir);
+            if (DEBUG) Slog.d(TAG, "Creating tasks directory " + sTasksDir);
             if (!sTasksDir.mkdir()) {
                 Slog.e(TAG, "Failure creating tasks directory " + sTasksDir);
             }
@@ -153,14 +129,12 @@
 
         sImagesDir = new File(systemDir, IMAGES_DIRNAME);
         if (!sImagesDir.exists()) {
-            if (DEBUG_PERSISTER) Slog.d(TAG, "Creating images directory " + sTasksDir);
+            if (DEBUG) Slog.d(TAG, "Creating images directory " + sTasksDir);
             if (!sImagesDir.mkdir()) {
                 Slog.e(TAG, "Failure creating images directory " + sImagesDir);
             }
         }
 
-        sRestoredTasksDir = new File(systemDir, RESTORED_TASKS_DIRNAME);
-
         mStackSupervisor = stackSupervisor;
         mService = stackSupervisor.mService;
         mRecentTasks = recentTasks;
@@ -179,8 +153,8 @@
             final WriteQueueItem item = mWriteQueue.get(queueNdx);
             if (item instanceof ImageWriteQueueItem &&
                     ((ImageWriteQueueItem) item).mFilename.startsWith(taskString)) {
-                if (DEBUG_PERSISTER) Slog.d(TAG, "Removing "
-                        + ((ImageWriteQueueItem) item).mFilename + " from write queue");
+                if (DEBUG) Slog.d(TAG, "Removing " + ((ImageWriteQueueItem) item).mFilename +
+                        " from write queue");
                 mWriteQueue.remove(queueNdx);
             }
         }
@@ -225,9 +199,9 @@
             } else if (mNextWriteTime == 0) {
                 mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS;
             }
-            if (DEBUG_PERSISTER) Slog.d(TAG, "wakeup: task=" + task + " flush=" + flush
-                    + " mNextWriteTime=" + mNextWriteTime + " mWriteQueue.size="
-                    + mWriteQueue.size() + " Callers=" + Debug.getCallers(4));
+            if (DEBUG) Slog.d(TAG, "wakeup: task=" + task + " flush=" + flush + " mNextWriteTime="
+                    + mNextWriteTime + " mWriteQueue.size=" + mWriteQueue.size()
+                    + " Callers=" + Debug.getCallers(4));
             notifyAll();
         }
 
@@ -269,7 +243,7 @@
             } else if (mNextWriteTime == 0) {
                 mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS;
             }
-            if (DEBUG_PERSISTER) Slog.d(TAG, "saveImage: filename=" + filename + " now=" +
+            if (DEBUG) Slog.d(TAG, "saveImage: filename=" + filename + " now=" +
                     SystemClock.uptimeMillis() + " mNextWriteTime=" +
                     mNextWriteTime + " Callers=" + Debug.getCallers(4));
             notifyAll();
@@ -303,12 +277,12 @@
     }
 
     private StringWriter saveToXml(TaskRecord task) throws IOException, XmlPullParserException {
-        if (DEBUG_PERSISTER) Slog.d(TAG, "saveToXml: task=" + task);
+        if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task);
         final XmlSerializer xmlSerializer = new FastXmlSerializer();
         StringWriter stringWriter = new StringWriter();
         xmlSerializer.setOutput(stringWriter);
 
-        if (DEBUG_PERSISTER) xmlSerializer.setFeature(
+        if (DEBUG) xmlSerializer.setFeature(
                     "http://xmlpull.org/v1/doc/features.html#indent-output", true);
 
         // save task
@@ -367,7 +341,7 @@
 
         for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
             File taskFile = recentFiles[taskNdx];
-            if (DEBUG_PERSISTER) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName());
+            if (DEBUG) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName());
             BufferedReader reader = null;
             boolean deleteFile = false;
             try {
@@ -380,12 +354,11 @@
                         event != XmlPullParser.END_TAG) {
                     final String name = in.getName();
                     if (event == XmlPullParser.START_TAG) {
-                        if (DEBUG_PERSISTER)
-                                Slog.d(TAG, "restoreTasksLocked: START_TAG name=" + name);
+                        if (DEBUG) Slog.d(TAG, "restoreTasksLocked: START_TAG name=" + name);
                         if (TAG_TASK.equals(name)) {
                             final TaskRecord task =
                                     TaskRecord.restoreFromXml(in, mStackSupervisor);
-                            if (DEBUG_PERSISTER) Slog.d(TAG, "restoreTasksLocked: restored task=" +
+                            if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task=" +
                                     task);
                             if (task != null) {
                                 task.isPersistable = true;
@@ -414,15 +387,14 @@
                 deleteFile = true;
             } finally {
                 IoUtils.closeQuietly(reader);
-                if (!DEBUG_PERSISTER && deleteFile) {
-                    if (true || DEBUG_PERSISTER)
-                            Slog.d(TAG, "Deleting file=" + taskFile.getName());
+                if (deleteFile) {
+                    if (DEBUG) Slog.d(TAG, "Deleting file=" + taskFile.getName());
                     taskFile.delete();
                 }
             }
         }
 
-        if (!DEBUG_PERSISTER) {
+        if (!DEBUG) {
             removeObsoleteFiles(recoveredTaskIds);
         }
 
@@ -453,8 +425,8 @@
     }
 
     private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
-        if (DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: persistentTaskIds="
-                    + persistentTaskIds + " files=" + files);
+        if (DEBUG) Slog.d(TAG, "removeObsoleteFile: persistentTaskIds=" + persistentTaskIds +
+                " files=" + files);
         if (files == null) {
             Slog.e(TAG, "File error accessing recents directory (too many files open?).");
             return;
@@ -467,15 +439,14 @@
                 final int taskId;
                 try {
                     taskId = Integer.valueOf(filename.substring(0, taskIdEnd));
-                    if (DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: Found taskId=" + taskId);
+                    if (DEBUG) Slog.d(TAG, "removeObsoleteFile: Found taskId=" + taskId);
                 } catch (Exception e) {
                     Slog.wtf(TAG, "removeObsoleteFile: Can't parse file=" + file.getName());
                     file.delete();
                     continue;
                 }
                 if (!persistentTaskIds.contains(taskId)) {
-                    if (true || DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: deleting file=" +
-                            file.getName());
+                    if (DEBUG) Slog.d(TAG, "removeObsoleteFile: deleting file=" + file.getName());
                     file.delete();
                 }
             }
@@ -488,441 +459,10 @@
     }
 
     static Bitmap restoreImage(String filename) {
-        if (DEBUG_PERSISTER) Slog.d(TAG, "restoreImage: restoring " + filename);
+        if (DEBUG) Slog.d(TAG, "restoreImage: restoring " + filename);
         return BitmapFactory.decodeFile(sImagesDir + File.separator + filename);
     }
 
-    /**
-     * Tries to restore task that were backed-up on a different device onto this device.
-     */
-    void restoreTasksFromOtherDeviceLocked() {
-        readOtherDeviceTasksFromDisk();
-        addOtherDeviceTasksToRecentsLocked();
-    }
-
-    /**
-     * Read the tasks that were backed-up on a different device and can be restored to this device
-     * from disk and populated {@link #mOtherDeviceTasksMap} with the information. Also sets up
-     * time to clear out other device tasks that have not been restored on this device
-     * within the allotted time.
-     */
-    private void readOtherDeviceTasksFromDisk() {
-        synchronized (mOtherDeviceTasksMap) {
-            // Clear out current map and expiration time.
-            mOtherDeviceTasksMap.clear();
-            mExpiredTasksCleanupTime = Long.MAX_VALUE;
-
-            final File[] taskFiles;
-            if (!sRestoredTasksDir.exists()
-                    || (taskFiles = sRestoredTasksDir.listFiles()) == null) {
-                // Nothing to do if there are no tasks to restore.
-                return;
-            }
-
-            long earliestMtime = System.currentTimeMillis();
-            SparseArray<List<OtherDeviceTask>> tasksByAffiliateIds =
-                        new SparseArray<>(taskFiles.length);
-
-            // Read new tasks from disk
-            for (int i = 0; i < taskFiles.length; ++i) {
-                final File taskFile = taskFiles[i];
-                if (DEBUG_RESTORER) Slog.d(TAG, "readOtherDeviceTasksFromDisk: taskFile="
-                            + taskFile.getName());
-
-                final OtherDeviceTask task = OtherDeviceTask.createFromFile(taskFile);
-
-                if (task == null) {
-                    // Go ahead and remove the file on disk if we are unable to create a task from
-                    // it.
-                    if (DEBUG_RESTORER) Slog.e(TAG, "Unable to create task for file="
-                                + taskFile.getName() + "...deleting file.");
-                    taskFile.delete();
-                    continue;
-                }
-
-                List<OtherDeviceTask> tasks = tasksByAffiliateIds.get(task.mAffiliatedTaskId);
-                if (tasks == null) {
-                    tasks = new ArrayList<>();
-                    tasksByAffiliateIds.put(task.mAffiliatedTaskId, tasks);
-                }
-                tasks.add(task);
-                final long taskMtime = taskFile.lastModified();
-                if (earliestMtime > taskMtime) {
-                    earliestMtime = taskMtime;
-                }
-            }
-
-            if (tasksByAffiliateIds.size() > 0) {
-                // Sort each affiliated tasks chain by taskId which is the order they were created
-                // that should always be correct...Then add to task map.
-                for (int i = 0; i < tasksByAffiliateIds.size(); i++) {
-                    List<OtherDeviceTask> chain = tasksByAffiliateIds.valueAt(i);
-                    Collections.sort(chain);
-                    // Package name of the root task in the affiliate chain.
-                    final String packageName =
-                            chain.get(chain.size()-1).mComponentName.getPackageName();
-                    List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.get(packageName);
-                    if (chains == null) {
-                        chains = new ArrayList<>();
-                        mOtherDeviceTasksMap.put(packageName, chains);
-                    }
-                    chains.add(chain);
-                }
-
-                // Set expiration time.
-                mExpiredTasksCleanupTime = earliestMtime + MAX_INSTALL_WAIT_TIME;
-                if (DEBUG_RESTORER) Slog.d(TAG, "Set Expiration time to "
-                            + DateUtils.formatDateTime(mService.mContext, mExpiredTasksCleanupTime,
-                            DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME));
-            }
-        }
-    }
-
-    /**
-     * Removed any expired tasks from {@link #mOtherDeviceTasksMap} and disk if their expiration
-     * time is less than or equal to {@link #mExpiredTasksCleanupTime}.
-     */
-    private void removeExpiredTasksIfNeeded() {
-        synchronized (mOtherDeviceTasksMap) {
-            final long now = System.currentTimeMillis();
-            final boolean noMoreTasks = mOtherDeviceTasksMap.isEmpty();
-            if (noMoreTasks || now < mExpiredTasksCleanupTime) {
-                if (noMoreTasks && mPackageUidMap != null) {
-                    // All done! package->uid map no longer needed.
-                    mPackageUidMap = null;
-                }
-                return;
-            }
-
-            long earliestNonExpiredMtime = now;
-            mExpiredTasksCleanupTime = Long.MAX_VALUE;
-
-            // Remove expired backed-up tasks that have not been restored. We only want to
-            // remove task if it is safe to remove all tasks in the affiliation chain.
-            for (int i = mOtherDeviceTasksMap.size() - 1; i >= 0 ; i--) {
-
-                List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.valueAt(i);
-                for (int j = chains.size() - 1; j >= 0 ; j--) {
-
-                    List<OtherDeviceTask> chain = chains.get(j);
-                    boolean removeChain = true;
-                    for (int k = chain.size() - 1; k >= 0 ; k--) {
-                        OtherDeviceTask task = chain.get(k);
-                        final long taskLastModified = task.mFile.lastModified();
-                        if ((taskLastModified + MAX_INSTALL_WAIT_TIME) > now) {
-                            // File has not expired yet...but we keep looping to get the earliest
-                            // mtime.
-                            if (earliestNonExpiredMtime > taskLastModified) {
-                                earliestNonExpiredMtime = taskLastModified;
-                            }
-                            removeChain = false;
-                        }
-                    }
-                    if (removeChain) {
-                        for (int k = chain.size() - 1; k >= 0; k--) {
-                            final File file = chain.get(k).mFile;
-                            if (DEBUG_RESTORER) Slog.d(TAG, "Deleting expired file="
-                                    + file.getName() + " mapped to not installed component="
-                                    + chain.get(k).mComponentName);
-                            file.delete();
-                        }
-                        chains.remove(j);
-                    }
-                }
-                if (chains.isEmpty()) {
-                    final String packageName = mOtherDeviceTasksMap.keyAt(i);
-                    mOtherDeviceTasksMap.removeAt(i);
-                    if (DEBUG_RESTORER) Slog.d(TAG, "Removed package=" + packageName
-                                + " from task map");
-                }
-            }
-
-            // Reset expiration time if there is any task remaining.
-            if (!mOtherDeviceTasksMap.isEmpty()) {
-                mExpiredTasksCleanupTime = earliestNonExpiredMtime + MAX_INSTALL_WAIT_TIME;
-                if (DEBUG_RESTORER) Slog.d(TAG, "Reset expiration time to "
-                            + DateUtils.formatDateTime(mService.mContext, mExpiredTasksCleanupTime,
-                            DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME));
-            } else {
-                // All done! package->uid map no longer needed.
-                mPackageUidMap = null;
-            }
-        }
-    }
-
-    /**
-     * Removes the input package name from the local package->uid map.
-     */
-    void removeFromPackageCache(String packageName) {
-        synchronized (mOtherDeviceTasksMap) {
-            if (mPackageUidMap != null) {
-                mPackageUidMap.remove(packageName);
-            }
-        }
-    }
-
-    /**
-     * Tries to add all backed-up tasks from another device to this device recent's list.
-     */
-    private void addOtherDeviceTasksToRecentsLocked() {
-        synchronized (mOtherDeviceTasksMap) {
-            for (int i = mOtherDeviceTasksMap.size() - 1; i >= 0; i--) {
-                addOtherDeviceTasksToRecentsLocked(mOtherDeviceTasksMap.keyAt(i));
-            }
-        }
-    }
-
-    /**
-     * Tries to add backed-up tasks that are associated with the input package from
-     * another device to this device recent's list.
-     */
-    void addOtherDeviceTasksToRecentsLocked(String packageName) {
-        synchronized (mOtherDeviceTasksMap) {
-            List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.get(packageName);
-            if (chains == null) {
-                return;
-            }
-
-            for (int i = chains.size() - 1; i >= 0; i--) {
-                List<OtherDeviceTask> chain = chains.get(i);
-                if (!canAddOtherDeviceTaskChain(chain)) {
-                    if (DEBUG_RESTORER) Slog.d(TAG, "Can't add task chain at index=" + i
-                            + " for package=" + packageName);
-                    continue;
-                }
-
-                // Generate task records for this chain.
-                List<TaskRecord> tasks = new ArrayList<>();
-                TaskRecord prev = null;
-                for (int j = chain.size() - 1; j >= 0; j--) {
-                    TaskRecord task = createTaskRecordLocked(chain.get(j));
-                    if (task == null) {
-                        // There was a problem in creating one of this task records in this chain.
-                        // There is no way we can continue...
-                        if (DEBUG_RESTORER) Slog.d(TAG, "Can't create task record for file="
-                                + chain.get(j).mFile + " for package=" + packageName);
-                        break;
-                    }
-
-                    // Wire-up affiliation chain.
-                    if (prev == null) {
-                        task.mPrevAffiliate = null;
-                        task.mPrevAffiliateTaskId = INVALID_TASK_ID;
-                        task.mAffiliatedTaskId = task.taskId;
-                    } else {
-                        prev.mNextAffiliate = task;
-                        prev.mNextAffiliateTaskId = task.taskId;
-                        task.mAffiliatedTaskId = prev.mAffiliatedTaskId;
-                        task.mPrevAffiliate = prev;
-                        task.mPrevAffiliateTaskId = prev.taskId;
-                    }
-                    prev = task;
-                    tasks.add(0, task);
-                }
-
-                // Add tasks to recent's if we were able to create task records for all the tasks
-                // in the chain.
-                if (tasks.size() == chain.size()) {
-                    // Make sure there is space in recent's to add the new task. If there is space
-                    // to the to the back.
-                    // TODO: Would be more fancy to interleave the new tasks into recent's based on
-                    // {@link TaskRecord.mLastTimeMoved} and drop the oldest recent's vs. just
-                    // adding to the back of the list.
-                    int spaceLeft =
-                            ActivityManager.getMaxRecentTasksStatic() - mRecentTasks.size();
-                    if (spaceLeft >= tasks.size()) {
-                        mRecentTasks.addAll(mRecentTasks.size(), tasks);
-                        for (int k = tasks.size() - 1; k >= 0; k--) {
-                            // Persist new tasks.
-                            wakeup(tasks.get(k), false);
-                        }
-
-                        if (DEBUG_RESTORER) Slog.d(TAG, "Added " + tasks.size()
-                                    + " tasks to recent's for" + " package=" + packageName);
-                    } else {
-                        if (DEBUG_RESTORER) Slog.d(TAG, "Didn't add to recents. tasks.size("
-                                    + tasks.size() + ") != chain.size(" + chain.size()
-                                    + ") for package=" + packageName);
-                    }
-                } else {
-                    if (DEBUG_RESTORER) Slog.v(TAG, "Unable to add restored tasks to recents "
-                            + tasks.size() + " tasks for package=" + packageName);
-                }
-
-                // Clean-up structures
-                for (int j = chain.size() - 1; j >= 0; j--) {
-                    chain.get(j).mFile.delete();
-                }
-                chains.remove(i);
-                if (chains.isEmpty()) {
-                    // The fate of all backed-up tasks associated with this package has been
-                    // determine. Go ahead and remove it from the to-process list.
-                    mOtherDeviceTasksMap.remove(packageName);
-                    if (DEBUG_RESTORER)
-                            Slog.d(TAG, "Removed package=" + packageName + " from restore map");
-                }
-            }
-        }
-    }
-
-    /**
-     * Creates and returns {@link TaskRecord} for the task from another device that can be used on
-     * this device. Returns null if the operation failed.
-     */
-    private TaskRecord createTaskRecordLocked(OtherDeviceTask other) {
-        File file = other.mFile;
-        BufferedReader reader = null;
-        TaskRecord task = null;
-        if (DEBUG_RESTORER) Slog.d(TAG, "createTaskRecordLocked: file=" + file.getName());
-
-        try {
-            reader = new BufferedReader(new FileReader(file));
-            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 (TAG_TASK.equals(name)) {
-                        // Create a task record using a task id that is valid for this device.
-                        task = TaskRecord.restoreFromXml(
-                                in, mStackSupervisor, mStackSupervisor.getNextTaskId());
-                        if (DEBUG_RESTORER)
-                                Slog.d(TAG, "createTaskRecordLocked: restored task=" + task);
-
-                        if (task != null) {
-                            task.isPersistable = true;
-                            task.inRecents = true;
-                            // Task can/should only be backed-up/restored for device owner.
-                            task.userId = UserHandle.USER_OWNER;
-                            // Clear out affiliated ids that are no longer valid on this device.
-                            task.mAffiliatedTaskId = INVALID_TASK_ID;
-                            task.mPrevAffiliateTaskId = INVALID_TASK_ID;
-                            task.mNextAffiliateTaskId = INVALID_TASK_ID;
-                            // Set up uids valid for this device.
-                            Integer uid = mPackageUidMap.get(task.realActivity.getPackageName());
-                            if (uid == null) {
-                                // How did this happen???
-                                Slog.wtf(TAG, "Can't find uid for task=" + task
-                                        + " in mPackageUidMap=" + mPackageUidMap);
-                                return null;
-                            }
-                            task.effectiveUid = task.mCallingUid = uid;
-                            for (int i = task.mActivities.size() - 1; i >= 0; --i) {
-                                final ActivityRecord activity = task.mActivities.get(i);
-                                uid = mPackageUidMap.get(activity.launchedFromPackage);
-                                if (uid == null) {
-                                    // How did this happen??
-                                    Slog.wtf(TAG, "Can't find uid for activity=" + activity
-                                            + " in mPackageUidMap=" + mPackageUidMap);
-                                    return null;
-                                }
-                                activity.launchedFromUid = uid;
-                            }
-
-                        } else {
-                            Slog.e(TAG, "Unable to create task for backed-up file=" + file + ": "
-                                        + fileToString(file));
-                        }
-                    } else {
-                        Slog.wtf(TAG, "createTaskRecordLocked Unknown xml event=" + event
-                                    + " name=" + name);
-                    }
-                }
-                XmlUtils.skipCurrentTag(in);
-            }
-        } catch (Exception e) {
-            Slog.wtf(TAG, "Unable to parse " + file + ". Error ", e);
-            Slog.e(TAG, "Failing file: " + fileToString(file));
-        } finally {
-            IoUtils.closeQuietly(reader);
-        }
-
-        return task;
-    }
-
-    /**
-     * Returns true if the input task chain backed-up from another device can be restored on this
-     * device. Also, sets the {@link OtherDeviceTask#mUid} on the input tasks if they can be
-     * restored.
-     */
-    private boolean canAddOtherDeviceTaskChain(List<OtherDeviceTask> chain) {
-
-        final ArraySet<ComponentName> validComponents = new ArraySet<>();
-        final IPackageManager pm = AppGlobals.getPackageManager();
-        for (int i = 0; i < chain.size(); i++) {
-
-            OtherDeviceTask task = chain.get(i);
-            // Quick check, we can't add the task chain if any of its task files don't exist.
-            if (!task.mFile.exists()) {
-                if (DEBUG_RESTORER) Slog.d(TAG,
-                        "Can't add chain due to missing file=" + task.mFile);
-                return false;
-            }
-
-            // Verify task package is installed.
-            if (!isPackageInstalled(task.mComponentName.getPackageName())) {
-                return false;
-            }
-            // Verify that all the launch packages are installed.
-            if (task.mLaunchPackages != null) {
-                for (int j = task.mLaunchPackages.size() - 1; j >= 0; --j) {
-                    if (!isPackageInstalled(task.mLaunchPackages.valueAt(j))) {
-                        return false;
-                    }
-                }
-            }
-
-            if (validComponents.contains(task.mComponentName)) {
-                // Existance of component has already been verified.
-                continue;
-            }
-
-            // Check to see if the specific component is installed.
-            try {
-                if (pm.getActivityInfo(task.mComponentName, 0, UserHandle.USER_OWNER) == null) {
-                    // Component isn't installed...
-                    return false;
-                }
-                validComponents.add(task.mComponentName);
-            } catch (RemoteException e) {
-                // Should not happen???
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Returns true if the input package name is installed. If the package is installed, an entry
-     * for the package is added to {@link #mPackageUidMap}.
-     */
-    private boolean isPackageInstalled(final String packageName) {
-        if (mPackageUidMap != null && mPackageUidMap.containsKey(packageName)) {
-            return true;
-        }
-        try {
-            int uid = AppGlobals.getPackageManager().getPackageUid(
-                    packageName, UserHandle.USER_OWNER);
-            if (uid == -1) {
-                // package doesn't exist...
-                return false;
-            }
-            if (mPackageUidMap == null) {
-                mPackageUidMap = new ArrayMap<>();
-            }
-            mPackageUidMap.put(packageName, uid);
-            return true;
-        } catch (RemoteException e) {
-            // Should not happen???
-            return false;
-        }
-    }
-
     private class LazyTaskWriterThread extends Thread {
 
         LazyTaskWriterThread(String name) {
@@ -941,21 +481,20 @@
                     probablyDone = mWriteQueue.isEmpty();
                 }
                 if (probablyDone) {
-                    if (DEBUG_PERSISTER) Slog.d(TAG, "Looking for obsolete files.");
+                    if (DEBUG) Slog.d(TAG, "Looking for obsolete files.");
                     persistentTaskIds.clear();
                     synchronized (mService) {
-                        if (DEBUG_PERSISTER) Slog.d(TAG, "mRecents=" + mRecentTasks);
+                        if (DEBUG) Slog.d(TAG, "mRecents=" + mRecentTasks);
                         for (int taskNdx = mRecentTasks.size() - 1; taskNdx >= 0; --taskNdx) {
                             final TaskRecord task = mRecentTasks.get(taskNdx);
-                            if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: task=" + task +
+                            if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task +
                                     " persistable=" + task.isPersistable);
                             if ((task.isPersistable || task.inRecents)
                                     && (task.stack == null || !task.stack.isHomeStack())) {
-                                if (DEBUG_PERSISTER)
-                                        Slog.d(TAG, "adding to persistentTaskIds task=" + task);
+                                if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
                                 persistentTaskIds.add(task.taskId);
                             } else {
-                                if (DEBUG_PERSISTER) Slog.d(TAG,
+                                if (DEBUG) Slog.d(TAG,
                                         "omitting from persistentTaskIds task=" + task);
                             }
                         }
@@ -969,7 +508,7 @@
                     if (mNextWriteTime != FLUSH_QUEUE) {
                         // The next write we don't have to wait so long.
                         mNextWriteTime = SystemClock.uptimeMillis() + INTER_WRITE_DELAY_MS;
-                        if (DEBUG_PERSISTER) Slog.d(TAG, "Next write time may be in " +
+                        if (DEBUG) Slog.d(TAG, "Next write time may be in " +
                                 INTER_WRITE_DELAY_MS + " msec. (" + mNextWriteTime + ")");
                     }
 
@@ -979,13 +518,8 @@
                             mNextWriteTime = 0; // idle.
                             TaskPersister.this.notifyAll(); // wake up flush() if needed.
                         }
-
-                        // See if we need to remove any expired back-up tasks before waiting.
-                        removeExpiredTasksIfNeeded();
-
                         try {
-                            if (DEBUG_PERSISTER)
-                                    Slog.d(TAG, "LazyTaskWriter: waiting indefinitely.");
+                            if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting indefinitely.");
                             TaskPersister.this.wait();
                         } catch (InterruptedException e) {
                         }
@@ -995,12 +529,11 @@
                     item = mWriteQueue.remove(0);
 
                     long now = SystemClock.uptimeMillis();
-                    if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: now=" + now
-                                + " mNextWriteTime=" + mNextWriteTime + " mWriteQueue.size="
-                                + mWriteQueue.size());
+                    if (DEBUG) Slog.d(TAG, "LazyTaskWriter: now=" + now + " mNextWriteTime=" +
+                            mNextWriteTime + " mWriteQueue.size=" + mWriteQueue.size());
                     while (now < mNextWriteTime) {
                         try {
-                            if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: waiting " +
+                            if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting " +
                                     (mNextWriteTime - now));
                             TaskPersister.this.wait(mNextWriteTime - now);
                         } catch (InterruptedException e) {
@@ -1015,7 +548,7 @@
                     ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
                     final String filename = imageWriteQueueItem.mFilename;
                     final Bitmap bitmap = imageWriteQueueItem.mImage;
-                    if (DEBUG_PERSISTER) Slog.d(TAG, "writing bitmap: filename=" + filename);
+                    if (DEBUG) Slog.d(TAG, "writing bitmap: filename=" + filename);
                     FileOutputStream imageFile = null;
                     try {
                         imageFile = new FileOutputStream(new File(sImagesDir, filename));
@@ -1029,12 +562,12 @@
                     // Write out one task.
                     StringWriter stringWriter = null;
                     TaskRecord task = ((TaskWriteQueueItem) item).mTask;
-                    if (DEBUG_PERSISTER) Slog.d(TAG, "Writing task=" + task);
+                    if (DEBUG) Slog.d(TAG, "Writing task=" + task);
                     synchronized (mService) {
                         if (task.inRecents) {
                             // Still there.
                             try {
-                                if (DEBUG_PERSISTER) Slog.d(TAG, "Saving task=" + task);
+                                if (DEBUG) Slog.d(TAG, "Saving task=" + task);
                                 stringWriter = saveToXml(task);
                             } catch (IOException e) {
                             } catch (XmlPullParserException e) {
@@ -1064,127 +597,4 @@
             }
         }
     }
-
-    /**
-     * Helper class for holding essential information about task that were backed-up on a different
-     * device that can be restored on this device.
-     */
-    private static class OtherDeviceTask implements Comparable<OtherDeviceTask> {
-        final File mFile;
-        // See {@link TaskRecord} for information on the fields below.
-        final ComponentName mComponentName;
-        final int mTaskId;
-        final int mAffiliatedTaskId;
-
-        // Names of packages that launched activities in this task. All packages listed here need
-        // to be installed on the current device in order for the task to be restored successfully.
-        final ArraySet<String> mLaunchPackages;
-
-        private OtherDeviceTask(File file, ComponentName componentName, int taskId,
-                int affiliatedTaskId, ArraySet<String> launchPackages) {
-            mFile = file;
-            mComponentName = componentName;
-            mTaskId = taskId;
-            mAffiliatedTaskId = (affiliatedTaskId == INVALID_TASK_ID) ? taskId: affiliatedTaskId;
-            mLaunchPackages = launchPackages;
-        }
-
-        @Override
-        public int compareTo(OtherDeviceTask another) {
-            return mTaskId - another.mTaskId;
-        }
-
-        /**
-         * Creates a new {@link OtherDeviceTask} object based on the contents of the input file.
-         *
-         * @param file input file that contains the complete task information.
-         * @return new {@link OtherDeviceTask} object or null if we failed to create the object.
-         */
-        static OtherDeviceTask createFromFile(File file) {
-            if (file == null || !file.exists()) {
-                if (DEBUG_RESTORER)
-                    Slog.d(TAG, "createFromFile: file=" + file + " doesn't exist.");
-                return null;
-            }
-
-            BufferedReader reader = null;
-
-            try {
-                reader = new BufferedReader(new FileReader(file));
-                final XmlPullParser in = Xml.newPullParser();
-                in.setInput(reader);
-
-                int event;
-                while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
-                        event != XmlPullParser.START_TAG) {
-                    // Skip to the start tag or end of document
-                }
-
-                if (event == XmlPullParser.START_TAG) {
-                    final String name = in.getName();
-
-                    if (TAG_TASK.equals(name)) {
-                        final int outerDepth = in.getDepth();
-                        ComponentName componentName = null;
-                        int taskId = INVALID_TASK_ID;
-                        int taskAffiliation = INVALID_TASK_ID;
-                        for (int j = in.getAttributeCount() - 1; j >= 0; --j) {
-                            final String attrName = in.getAttributeName(j);
-                            final String attrValue = in.getAttributeValue(j);
-                            if (TaskRecord.ATTR_REALACTIVITY.equals(attrName)) {
-                                componentName = ComponentName.unflattenFromString(attrValue);
-                            } else if (TaskRecord.ATTR_TASKID.equals(attrName)) {
-                                taskId = Integer.valueOf(attrValue);
-                            } else if (TaskRecord.ATTR_TASK_AFFILIATION.equals(attrName)) {
-                                taskAffiliation = Integer.valueOf(attrValue);
-                            }
-                        }
-                        if (componentName == null || taskId == INVALID_TASK_ID) {
-                            if (DEBUG_RESTORER) Slog.e(TAG,
-                                    "createFromFile: FAILED componentName=" + componentName
-                                    + " taskId=" + taskId + " file=" + file);
-                            return null;
-                        }
-
-                        ArraySet<String> launchPackages = null;
-                        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
-                                (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
-                            if (event == XmlPullParser.START_TAG) {
-                                if (TaskRecord.TAG_ACTIVITY.equals(in.getName())) {
-                                    for (int j = in.getAttributeCount() - 1; j >= 0; --j) {
-                                        if (ActivityRecord.ATTR_LAUNCHEDFROMPACKAGE.equals(
-                                                in.getAttributeName(j))) {
-                                            if (launchPackages == null) {
-                                                launchPackages = new ArraySet();
-                                            }
-                                            launchPackages.add(in.getAttributeValue(j));
-                                        }
-                                    }
-                                } else {
-                                    XmlUtils.skipCurrentTag(in);
-                                }
-                            }
-                        }
-                        if (DEBUG_RESTORER) Slog.d(TAG, "creating OtherDeviceTask from file="
-                                + file.getName() + " componentName=" + componentName
-                                + " taskId=" + taskId + " launchPackages=" + launchPackages);
-                        return new OtherDeviceTask(file, componentName, taskId,
-                                taskAffiliation, launchPackages);
-                    } else {
-                        Slog.wtf(TAG,
-                                "createFromFile: Unknown xml event=" + event + " name=" + name);
-                    }
-                } else {
-                    Slog.wtf(TAG, "createFromFile: Unable to find start tag in file=" + file);
-                }
-            } catch (IOException | XmlPullParserException e) {
-                Slog.wtf(TAG, "Unable to parse " + file + ". Error ", e);
-            } finally {
-                IoUtils.closeQuietly(reader);
-            }
-
-            // Something went wrong...
-            return null;
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index f653e9e..417c7c3 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -28,8 +28,6 @@
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
-import static com.android.server.am.TaskPersister.DEBUG_PERSISTER;
-import static com.android.server.am.TaskPersister.DEBUG_RESTORER;
 
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -71,7 +69,7 @@
     private static final String TAG_AFFINITYINTENT = "affinity_intent";
     static final String ATTR_REALACTIVITY = "real_activity";
     private static final String ATTR_ORIGACTIVITY = "orig_activity";
-    static final String TAG_ACTIVITY = "activity";
+    private static final String TAG_ACTIVITY = "activity";
     private static final String ATTR_AFFINITY = "affinity";
     private static final String ATTR_ROOT_AFFINITY = "root_affinity";
     private static final String ATTR_ROOTHASRESET = "root_has_reset";
@@ -970,10 +968,6 @@
 
     static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
             throws IOException, XmlPullParserException {
-        return restoreFromXml(in, stackSupervisor, INVALID_TASK_ID);
-    }
-    static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor,
-            int inTaskId) throws IOException, XmlPullParserException {
         Intent intent = null;
         Intent affinityIntent = null;
         ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
@@ -993,7 +987,7 @@
         long lastActiveTime = -1;
         long lastTimeOnTop = 0;
         boolean neverRelinquishIdentity = true;
-        int taskId = inTaskId;
+        int taskId = INVALID_TASK_ID;
         final int outerDepth = in.getDepth();
         TaskDescription taskDescription = new TaskDescription();
         int taskAffiliation = INVALID_TASK_ID;
@@ -1008,8 +1002,8 @@
         for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
             final String attrName = in.getAttributeName(attrNdx);
             final String attrValue = in.getAttributeValue(attrNdx);
-            if (DEBUG_PERSISTER || DEBUG_RESTORER) Slog.d(TaskPersister.TAG,
-                        "TaskRecord: attribute name=" + attrName + " value=" + attrValue);
+            if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
+                    attrName + " value=" + attrValue);
             if (ATTR_TASKID.equals(attrName)) {
                 if (taskId == INVALID_TASK_ID) taskId = Integer.valueOf(attrValue);
             } else if (ATTR_REALACTIVITY.equals(attrName)) {
@@ -1071,16 +1065,16 @@
                 (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
             if (event == XmlPullParser.START_TAG) {
                 final String name = in.getName();
-                if (DEBUG_PERSISTER || DEBUG_RESTORER)
-                        Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" + name);
+                if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
+                        name);
                 if (TAG_AFFINITYINTENT.equals(name)) {
                     affinityIntent = Intent.restoreFromXml(in);
                 } else if (TAG_INTENT.equals(name)) {
                     intent = Intent.restoreFromXml(in);
                 } else if (TAG_ACTIVITY.equals(name)) {
                     ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor);
-                    if (DEBUG_PERSISTER || DEBUG_RESTORER)
-                            Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + activity);
+                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
+                            activity);
                     if (activity != null) {
                         activities.add(activity);
                     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 4e83992..fba9258 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -149,7 +149,6 @@
     /**
      * Force evaluation even if it has succeeded in the past.
      * arg1 = UID responsible for requesting this reeval.  Will be billed for data.
-     * arg2 = Number of evaluation attempts to make. (If 0, make INITIAL_ATTEMPTS attempts.)
      */
     public static final int CMD_FORCE_REEVALUATION = BASE + 8;
 
@@ -183,20 +182,18 @@
     private final int mLingerDelayMs;
     private int mLingerToken = 0;
 
-    // Negative values disable reevaluation.
-    private static final String REEVALUATE_DELAY_PROPERTY = "persist.netmon.reeval_delay";
-    // When connecting, attempt to validate 3 times, pausing 5s between them.
-    private static final int DEFAULT_REEVALUATE_DELAY_MS = 5000;
-    private static final int INITIAL_ATTEMPTS = 3;
-    // If a network is not validated, make one attempt every 10 mins to see if it starts working.
-    private static final int REEVALUATE_PAUSE_MS = 10*60*1000;
-    private static final int PERIODIC_ATTEMPTS = 1;
-    // When an application calls reportNetworkConnectivity, only make one attempt.
-    private static final int REEVALUATE_ATTEMPTS = 1;
-    private final int mReevaluateDelayMs;
+    // Start mReevaluateDelayMs at this value and double.
+    private static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
+    private static final int MAX_REEVALUATE_DELAY_MS = 10*60*1000;
+    // Before network has been evaluated this many times, ignore repeated reevaluate requests.
+    private static final int IGNORE_REEVALUATE_ATTEMPTS = 5;
     private int mReevaluateToken = 0;
     private static final int INVALID_UID = -1;
     private int mUidResponsibleForReeval = INVALID_UID;
+    // When network has been evaluated this many times:
+    //   1. report NETWORK_TEST_RESULT_INVALID
+    //   2. stop blaming UID that requested re-evaluation for further attempts
+    private static final int INITIAL_EVALUATION_ATTEMPTS = 3;
 
     private final Context mContext;
     private final Handler mConnectivityServiceHandler;
@@ -211,19 +208,12 @@
 
     // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app.
     private boolean mUserDoesNotWant = false;
-
-    // How many times we should attempt validation. Only checked in EvaluatingState; must be set
-    // before entering EvaluatingState. Note that whatever code causes us to transition to
-    // EvaluatingState last decides how many attempts will be made, so if one codepath were to
-    // enter EvaluatingState with a specific number of attempts, and then another were to enter it
-    // with a different number of attempts, the second number would be used. This is not currently
-    // a problem because EvaluatingState is not reentrant.
-    private int mMaxAttempts;
+    // Avoids surfacing "Sign in to network" notification.
+    private boolean mDontDisplaySigninNotification = false;
 
     public boolean systemReady = false;
 
     private final State mDefaultState = new DefaultState();
-    private final State mOfflineState = new OfflineState();
     private final State mValidatedState = new ValidatedState();
     private final State mMaybeNotifyState = new MaybeNotifyState();
     private final State mEvaluatingState = new EvaluatingState();
@@ -247,7 +237,6 @@
         mDefaultRequest = defaultRequest;
 
         addState(mDefaultState);
-        addState(mOfflineState, mDefaultState);
         addState(mValidatedState, mDefaultState);
         addState(mMaybeNotifyState, mDefaultState);
             addState(mEvaluatingState, mMaybeNotifyState);
@@ -260,8 +249,6 @@
         if (mServer == null) mServer = DEFAULT_SERVER;
 
         mLingerDelayMs = SystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
-        mReevaluateDelayMs = SystemProperties.getInt(REEVALUATE_DELAY_PROPERTY,
-                DEFAULT_REEVALUATE_DELAY_MS);
 
         mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1;
@@ -289,7 +276,6 @@
                     return HANDLED;
                 case CMD_NETWORK_CONNECTED:
                     if (DBG) log("Connected");
-                    mMaxAttempts = INITIAL_ATTEMPTS;
                     transitionTo(mEvaluatingState);
                     return HANDLED;
                 case CMD_NETWORK_DISCONNECTED:
@@ -303,7 +289,6 @@
                 case CMD_FORCE_REEVALUATION:
                     if (DBG) log("Forcing reevaluation");
                     mUidResponsibleForReeval = message.arg1;
-                    mMaxAttempts = message.arg2 != 0 ? message.arg2 : REEVALUATE_ATTEMPTS;
                     transitionTo(mEvaluatingState);
                     return HANDLED;
                 case CMD_CAPTIVE_PORTAL_APP_FINISHED:
@@ -313,18 +298,23 @@
                     mCaptivePortalLoggedInResponseToken = String.valueOf(new Random().nextLong());
                     switch (message.arg1) {
                         case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_DISMISSED:
-                            sendMessage(CMD_FORCE_REEVALUATION, 0 /* no UID */,
-                                    0 /* INITIAL_ATTEMPTS */);
+                            sendMessage(CMD_FORCE_REEVALUATION, 0 /* no UID */, 0);
                             break;
                         case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS:
+                            mDontDisplaySigninNotification = true;
                             // TODO: Distinguish this from a network that actually validates.
                             // Displaying the "!" on the system UI icon may still be a good idea.
                             transitionTo(mValidatedState);
                             break;
                         case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_UNWANTED:
+                            mDontDisplaySigninNotification = true;
                             mUserDoesNotWant = true;
+                            mConnectivityServiceHandler.sendMessage(obtainMessage(
+                                    EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, 0,
+                                    mNetworkAgentInfo));
                             // TODO: Should teardown network.
-                            transitionTo(mOfflineState);
+                            mUidResponsibleForReeval = 0;
+                            transitionTo(mEvaluatingState);
                             break;
                     }
                     return HANDLED;
@@ -334,42 +324,6 @@
         }
     }
 
-    // Being in the OfflineState State indicates a Network is unwanted or failed validation.
-    private class OfflineState extends State {
-        @Override
-        public void enter() {
-            mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
-                    NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo));
-            if (!mUserDoesNotWant) {
-                sendMessageDelayed(CMD_FORCE_REEVALUATION, 0 /* no UID */,
-                        PERIODIC_ATTEMPTS, REEVALUATE_PAUSE_MS);
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) log(getName() + message.toString());
-                        switch (message.what) {
-                case CMD_FORCE_REEVALUATION:
-                    // If the user has indicated they explicitly do not want to use this network,
-                    // don't allow a reevaluation as this will be pointless and could result in
-                    // the user being annoyed with repeated unwanted notifications.
-                    return mUserDoesNotWant ? HANDLED : NOT_HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-             // NOTE: This removes the delayed message posted by enter() but will inadvertently
-             // remove any other CMD_FORCE_REEVALUATION in the message queue.  At the moment this
-             // is harmless.  If in the future this becomes problematic a different message could
-             // be used.
-             removeMessages(CMD_FORCE_REEVALUATION);
-        }
-    }
-
     // Being in the ValidatedState State indicates a Network is:
     // - Successfully validated, or
     // - Wanted "as is" by the user, or
@@ -426,18 +380,20 @@
     }
 
     // Being in the EvaluatingState State indicates the Network is being evaluated for internet
-    // connectivity.
+    // connectivity, or that the user has indicated that this network is unwanted.
     private class EvaluatingState extends State {
-        private int mAttempt;
+        private int mReevaluateDelayMs;
+        private int mAttempts;
 
         @Override
         public void enter() {
-            mAttempt = 1;
             sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
             if (mUidResponsibleForReeval != INVALID_UID) {
                 TrafficStats.setThreadStatsUid(mUidResponsibleForReeval);
                 mUidResponsibleForReeval = INVALID_UID;
             }
+            mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS;
+            mAttempts = 0;
         }
 
         @Override
@@ -445,7 +401,7 @@
             if (DBG) log(getName() + message.toString());
             switch (message.what) {
                 case CMD_REEVALUATE:
-                    if (message.arg1 != mReevaluateToken)
+                    if (message.arg1 != mReevaluateToken || mUserDoesNotWant)
                         return HANDLED;
                     // Don't bother validating networks that don't satisify the default request.
                     // This includes:
@@ -469,6 +425,7 @@
                         transitionTo(mValidatedState);
                         return HANDLED;
                     }
+                    mAttempts++;
                     // Note: This call to isCaptivePortal() could take up to a minute. Resolving the
                     // server's IP addresses could hit the DNS timeout, and attempting connections
                     // to each of the server's several IP addresses (currently one IPv4 and one
@@ -480,16 +437,27 @@
                         transitionTo(mValidatedState);
                     } else if (httpResponseCode >= 200 && httpResponseCode <= 399) {
                         transitionTo(mCaptivePortalState);
-                    } else if (++mAttempt > mMaxAttempts) {
-                        transitionTo(mOfflineState);
-                    } else if (mReevaluateDelayMs >= 0) {
+                    } else {
                         Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
                         sendMessageDelayed(msg, mReevaluateDelayMs);
+                        if (mAttempts >= INITIAL_EVALUATION_ATTEMPTS) {
+                            mConnectivityServiceHandler.sendMessage(obtainMessage(
+                                    EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, 0,
+                                    mNetworkAgentInfo));
+                            // Don't continue to blame UID forever.
+                            TrafficStats.clearThreadStatsUid();
+                        }
+                        mReevaluateDelayMs *= 2;
+                        if (mReevaluateDelayMs > MAX_REEVALUATE_DELAY_MS) {
+                            mReevaluateDelayMs = MAX_REEVALUATE_DELAY_MS;
+                        }
                     }
                     return HANDLED;
                 case CMD_FORCE_REEVALUATION:
-                    // Ignore duplicate requests.
-                    return HANDLED;
+                    // Before IGNORE_REEVALUATE_ATTEMPTS attempts are made,
+                    // ignore any re-evaluation requests. After, restart the
+                    // evaluation process via EvaluatingState#enter.
+                    return mAttempts < IGNORE_REEVALUATE_ATTEMPTS ? HANDLED : NOT_HANDLED;
                 default:
                     return NOT_HANDLED;
             }
@@ -533,6 +501,8 @@
         public void enter() {
             mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
                     NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo));
+            // Don't annoy user with sign-in notifications.
+            if (mDontDisplaySigninNotification) return;
             // Create a CustomIntentReceiver that sends us a
             // CMD_LAUNCH_CAPTIVE_PORTAL_APP message when the user
             // touches the notification.
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index aeecdf3..e1ec8a6 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -298,13 +298,15 @@
     }
 
     /**
-     * Set whether the current package has the ability to launch VPNs without user intervention.
+     * Set whether a package has the ability to launch VPNs without user intervention.
      */
-    public void setPackageAuthorization(boolean authorized) {
+    public void setPackageAuthorization(String packageName, boolean authorized) {
         // Check if the caller is authorized.
         enforceControlPermission();
 
-        if (mPackage == null || VpnConfig.LEGACY_VPN.equals(mPackage)) {
+        int uid = getAppUid(packageName, mUserHandle);
+        if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
+            // Authorization for nonexistent packages (or fake ones) can't be updated.
             return;
         }
 
@@ -312,10 +314,10 @@
         try {
             AppOpsManager appOps =
                     (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
-            appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, mOwnerUID, mPackage,
+            appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName,
                     authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
         } catch (Exception e) {
-            Log.wtf(TAG, "Failed to set app ops for package " + mPackage, e);
+            Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 0db3e3f..97ada15 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -88,6 +88,11 @@
     public static final int FLAG_OWN_CONTENT_ONLY = 1 << 7;
 
     /**
+     * Flag: This display device has a round shape.
+     */
+    public static final int FLAG_ROUND = 1 << 8;
+
+    /**
      * Touch attachment: Display does not receive touch.
      */
     public static final int TOUCH_NONE = 0;
@@ -385,6 +390,9 @@
         if ((flags & FLAG_OWN_CONTENT_ONLY) != 0) {
             msg.append(", FLAG_OWN_CONTENT_ONLY");
         }
+        if ((flags & FLAG_ROUND) != 0) {
+            msg.append(", FLAG_ROUND");
+        }
         return msg.toString();
     }
 }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index cc7d848..517a825 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -16,6 +16,8 @@
 
 package com.android.server.display;
 
+import android.content.res.Resources;
+import android.os.Build;
 import com.android.server.LocalServices;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
@@ -49,6 +51,8 @@
 
     private static final String UNIQUE_ID_PREFIX = "local:";
 
+    private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
+
     private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
             SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
             SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
@@ -267,10 +271,16 @@
                 }
 
                 if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
-                    mInfo.name = getContext().getResources().getString(
+                    final Resources res = getContext().getResources();
+                    mInfo.name = res.getString(
                             com.android.internal.R.string.display_manager_built_in_display_name);
                     mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
                             | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
+                    if (res.getBoolean(com.android.internal.R.bool.config_mainBuiltInDisplayIsRound)
+                            || (Build.HARDWARE.contains("goldfish")
+                            && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
+                        mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
+                    }
                     mInfo.type = Display.TYPE_BUILT_IN;
                     mInfo.densityDpi = (int)(phys.density * 160 + 0.5f);
                     mInfo.xDpi = phys.xDpi;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 424b4a0..4823769 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -217,6 +217,9 @@
             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRESENTATION) != 0) {
                 mBaseDisplayInfo.flags |= Display.FLAG_PRESENTATION;
             }
+            if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ROUND) != 0) {
+                mBaseDisplayInfo.flags |= Display.FLAG_ROUND;
+            }
             mBaseDisplayInfo.type = deviceInfo.type;
             mBaseDisplayInfo.address = deviceInfo.address;
             mBaseDisplayInfo.name = deviceInfo.name;
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index f16fcb0..d725d94 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -626,16 +626,16 @@
     public void onStart() {
         publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
         mHalDeviceId = nativeOpenHal();
-        if (mHalDeviceId != 0) {
-            updateActiveGroup(ActivityManager.getCurrentUser());
-        }
+        updateActiveGroup(ActivityManager.getCurrentUser());
         if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
         listenForUserSwitches();
     }
 
     private void updateActiveGroup(int userId) {
-        File path = Environment.getUserSystemDirectory(userId);
-        nativeSetActiveGroup(userId, path.getAbsolutePath().getBytes());
+        if (mHalDeviceId != 0) {
+            File path = Environment.getUserSystemDirectory(userId);
+            nativeSetActiveGroup(userId, path.getAbsolutePath().getBytes());
+        }
     }
 
     private void listenForUserSwitches() {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 311ca65..ef4da02 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -660,6 +660,7 @@
                 String[] newlyVisibleKeys, String[] noLongerVisibleKeys) {
             // Using ';' as separator since eventlogs uses ',' to separate
             // args.
+            // TODO remove this: b/21248682
             EventLogTags.writeNotificationVisibilityChanged(
                     TextUtils.join(";", newlyVisibleKeys),
                     TextUtils.join(";", noLongerVisibleKeys));
@@ -667,7 +668,7 @@
                 for (String key : newlyVisibleKeys) {
                     NotificationRecord r = mNotificationsByKey.get(key);
                     if (r == null) continue;
-                    r.stats.onVisibilityChanged(true);
+                    r.setVisibility(true);
                 }
                 // Note that we might receive this event after notifications
                 // have already left the system, e.g. after dismissing from the
@@ -676,7 +677,7 @@
                 for (String key : noLongerVisibleKeys) {
                     NotificationRecord r = mNotificationsByKey.get(key);
                     if (r == null) continue;
-                    r.stats.onVisibilityChanged(false);
+                    r.setVisibility(false);
                 }
             }
         }
@@ -2784,8 +2785,11 @@
         // Save it for users of getHistoricalNotifications()
         mArchive.record(r.sbn);
 
-        int lifespan = (int) (System.currentTimeMillis() - r.getCreationTimeMs());
-        EventLogTags.writeNotificationCanceled(canceledKey, reason, lifespan);
+        final long now = System.currentTimeMillis();
+        final int lifespan = (int) (now - r.getCreationTimeMs());
+        final long visibleSinceMs = r.getVisibleSinceMs();
+        final int exposure = visibleSinceMs == 0L ? 0 : (int) (now - visibleSinceMs);
+        EventLogTags.writeNotificationCanceled(canceledKey, reason, lifespan, exposure);
     }
 
     /**
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 02cc840..b8478c1 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -26,6 +26,7 @@
 import android.service.notification.StatusBarNotification;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
 import java.lang.reflect.Array;
@@ -68,6 +69,12 @@
     // The first post time, stable across updates.
     private long mCreationTimeMs;
 
+    // The most recent visibility event.
+    private long mVisibleSinceMs;
+
+    // The most recent update time, or the creation time if no updates.
+    private long mUpdateTimeMs;
+
     // Is this record an update of an old record?
     public boolean isUpdate;
     private int mPackagePriority;
@@ -84,6 +91,7 @@
         mOriginalFlags = sbn.getNotification().flags;
         mRankingTimeMs = calculateRankingTimeMs(0L);
         mCreationTimeMs = sbn.getPostTime();
+        mUpdateTimeMs = mCreationTimeMs;
     }
 
     // copy any notes that the ranking system may have made before the update
@@ -95,6 +103,7 @@
         mIntercept = previous.mIntercept;
         mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
         mCreationTimeMs = previous.mCreationTimeMs;
+        mVisibleSinceMs = previous.mVisibleSinceMs;
         // Don't copy mGlobalSortKey, recompute it.
     }
 
@@ -181,6 +190,8 @@
         pw.println(prefix + "  mGlobalSortKey=" + mGlobalSortKey);
         pw.println(prefix + "  mRankingTimeMs=" + mRankingTimeMs);
         pw.println(prefix + "  mCreationTimeMs=" + mCreationTimeMs);
+        pw.println(prefix + "  mVisibleSinceMs=" + mVisibleSinceMs);
+        pw.println(prefix + "  mUpdateTimeMs=" + mUpdateTimeMs);
     }
 
 
@@ -277,6 +288,13 @@
     }
 
     /**
+     * Returns the timestamp of the most recent updates, or the post time if none.
+     */
+    public long getUpdateTimeMs() {
+        return mUpdateTimeMs;
+    }
+
+    /**
      * Returns the timestamp of the first post, ignoring updates.
      */
     public long getCreationTimeMs() {
@@ -284,6 +302,25 @@
     }
 
     /**
+     * Returns the timestamp of the most recent visibility event, or 0L if hidden.
+     */
+    public long getVisibleSinceMs() {
+        return mVisibleSinceMs;
+    }
+
+    /**
+     * Set the visibility of the notification.
+     */
+    public void setVisibility(boolean visible) {
+        final long now = System.currentTimeMillis();
+        mVisibleSinceMs = visible ? now : 0L;
+        stats.onVisibilityChanged(visible);
+        EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0,
+                (int) (now - mCreationTimeMs),
+                (int) (now - mUpdateTimeMs));
+    }
+
+    /**
      * @param previousRankingTimeMs for updated notifications, {@link #getRankingTimeMs()}
      *     of the previous notification record, 0 otherwise
      */
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 185ef03..a4e9c68 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1220,9 +1220,7 @@
     };
 
     private boolean isRoundWindow() {
-        return mContext.getResources().getBoolean(com.android.internal.R.bool.config_windowIsRound)
-                || (Build.HARDWARE.contains("goldfish")
-                && SystemProperties.getBoolean(ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false));
+        return mContext.getResources().getConfiguration().isScreenRound();
     }
 
     /** {@inheritDoc} */
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 91ce739..482ae24 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -432,8 +432,7 @@
                 mDrawBorderInset = (int) mBorderWidth / 2;
                 mWindow = new ViewportWindow(mContext);
 
-                if (mContext.getResources().getBoolean(
-                            com.android.internal.R.bool.config_windowIsRound)) {
+                if (mContext.getResources().getConfiguration().isScreenRound()) {
                     mCircularPath = new Path();
                     mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
                     final int centerXY = mTempPoint.x / 2;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4972ce4..d94f5d9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5923,8 +5923,7 @@
 
     public void updateCircularDisplayMaskIfNeeded() {
         // we're fullscreen and not hosted in an ActivityView
-        if (mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_windowIsRound)
+        if (mContext.getResources().getConfiguration().isScreenRound()
                 && mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_windowShowCircularMask)) {
             // Device configuration calls for a circular display mask, but we only enable the mask
@@ -6380,10 +6379,9 @@
             }
         }
 
-        // Copy the screenshot bitmap to another buffer so that the gralloc backed
-        // bitmap will not have a long lifetime. Gralloc memory can be pinned or
-        // duplicated and might have a higher cost than a skia backed buffer.
-        Bitmap ret = bm.copy(bm.getConfig(),true);
+        // Create a copy of the screenshot that is immutable and backed in ashmem.
+        // This greatly reduces the overhead of passing the bitmap between processes.
+        Bitmap ret = bm.createAshmemBitmap();
         bm.recycle();
         return ret;
     }
@@ -7342,6 +7340,11 @@
         computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, mDisplayMetrics.density,
                 config);
 
+        config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
+                | ((displayInfo.flags & Display.FLAG_ROUND) != 0
+                        ? Configuration.SCREENLAYOUT_ROUND_YES
+                        : Configuration.SCREENLAYOUT_ROUND_NO);
+
         config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
         config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
         config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated,
@@ -9973,6 +9976,7 @@
                             winAnimator.setAnimation(a);
                             winAnimator.mAnimDw = w.mLastFrame.left - left;
                             winAnimator.mAnimDh = w.mLastFrame.top - top;
+                            winAnimator.mAnimateMove = true;
                         }
 
                         //TODO (multidisplay): Accessibility supported only for the default display.
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index ec89b37..424e2e2 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -122,6 +122,7 @@
     // used.
     int mAnimDw;
     int mAnimDh;
+    boolean mAnimateMove = false;
     float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
     float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
 
@@ -290,9 +291,15 @@
                         " wh=" + mWin.mFrame.height() +
                         " dw=" + mAnimDw + " dh=" + mAnimDh +
                         " scale=" + mService.getWindowAnimationScaleLocked());
-                    mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
-                            mAnimDw, mAnimDh);
                     final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+                    if (mAnimateMove) {
+                        mAnimateMove = false;
+                        mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
+                                mAnimDw, mAnimDh);
+                    } else {
+                        mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
+                                displayInfo.appWidth, displayInfo.appHeight);
+                    }
                     mAnimDw = displayInfo.appWidth;
                     mAnimDh = displayInfo.appHeight;
                     mAnimation.setStartTime(mAnimationStartTime != -1
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 42eb6c3..03abfba 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -35,6 +35,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.IVoiceInteractionSessionService;
 import android.service.voice.VoiceInteractionService;
@@ -177,6 +178,8 @@
 
     public boolean showLocked(Bundle args, int flags,
             IVoiceInteractionSessionShowCallback showCallback) {
+        // For now we never allow screenshots.
+        flags &= ~VoiceInteractionService.START_WITH_SCREENSHOT;
         if (mBound) {
             if (!mFullyBound) {
                 mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
@@ -190,7 +193,8 @@
             mHaveAssistData = false;
             if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
                 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid,
-                        mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED) {
+                        mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
+                        && isStructureEnabled()) {
                     try {
                         mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
                                 mAssistReceiver);
@@ -455,6 +459,11 @@
         }
     }
 
+    private boolean isStructureEnabled() {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, mUser) != 0;
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mToken="); pw.println(mToken);
         pw.print(prefix); pw.print("mShown="); pw.println(mShown);
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
index ede9e99..b12867a 100644
--- a/tools/aapt/AaptConfig.cpp
+++ b/tools/aapt/AaptConfig.cpp
@@ -123,6 +123,14 @@
         part = parts[index].string();
     }
 
+    if (parseScreenRound(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
     if (parseOrientation(part, &config)) {
         index++;
         if (index == N) {
@@ -241,7 +249,9 @@
     }
 
     uint16_t minSdk = 0;
-    if (config->density == ResTable_config::DENSITY_ANY) {
+    if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
+        minSdk = SDK_MNC;
+    } else if (config->density == ResTable_config::DENSITY_ANY) {
         minSdk = SDK_LOLLIPOP;
     } else if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
             || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
@@ -395,7 +405,26 @@
                 | ResTable_config::SCREENLONG_NO;
         return true;
     }
+    return false;
+}
 
+bool parseScreenRound(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->screenLayout2 =
+                (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
+                | ResTable_config::SCREENROUND_ANY;
+        return true;
+    } else if (strcmp(name, "round") == 0) {
+        if (out) out->screenLayout2 =
+                (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
+                | ResTable_config::SCREENROUND_YES;
+        return true;
+    } else if (strcmp(name, "notround") == 0) {
+        if (out) out->screenLayout2 =
+                (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
+                | ResTable_config::SCREENROUND_NO;
+        return true;
+    }
     return false;
 }
 
diff --git a/tools/aapt/AaptConfig.h b/tools/aapt/AaptConfig.h
index f73a5081..04c763f 100644
--- a/tools/aapt/AaptConfig.h
+++ b/tools/aapt/AaptConfig.h
@@ -60,6 +60,7 @@
 bool parseScreenHeightDp(const char* str, android::ResTable_config* out = NULL);
 bool parseScreenLayoutSize(const char* str, android::ResTable_config* out = NULL);
 bool parseScreenLayoutLong(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenRound(const char* name, android::ResTable_config* out = NULL);
 bool parseOrientation(const char* str, android::ResTable_config* out = NULL);
 bool parseUiModeType(const char* str, android::ResTable_config* out = NULL);
 bool parseUiModeNight(const char* str, android::ResTable_config* out = NULL);
diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h
index 4e0fe10..16e622a 100644
--- a/tools/aapt/SdkConstants.h
+++ b/tools/aapt/SdkConstants.h
@@ -38,6 +38,7 @@
     SDK_KITKAT_WATCH = 20,
     SDK_LOLLIPOP = 21,
     SDK_LOLLIPOP_MR1 = 22,
+    SDK_MNC = 23,
 };
 
 #endif // H_AAPT_SDK_CONSTANTS
diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp
index 7618974..8bb38ba 100644
--- a/tools/aapt/tests/AaptConfig_test.cpp
+++ b/tools/aapt/tests/AaptConfig_test.cpp
@@ -19,6 +19,7 @@
 
 #include "AaptConfig.h"
 #include "ConfigDescription.h"
+#include "SdkConstants.h"
 #include "TestHelper.h"
 
 using android::String8;
@@ -82,3 +83,18 @@
     EXPECT_TRUE(TestParse("car", &config));
     EXPECT_EQ(android::ResTable_config::UI_MODE_TYPE_CAR, config.uiMode);
 }
+
+TEST(AaptConfigTest, TestParsingRoundQualifier) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("round", &config));
+    EXPECT_EQ(android::ResTable_config::SCREENROUND_YES,
+              config.screenLayout2 & android::ResTable_config::MASK_SCREENROUND);
+    EXPECT_EQ(SDK_MNC, config.sdkVersion);
+    EXPECT_EQ(String8("round-v23"), config.toString());
+
+    EXPECT_TRUE(TestParse("notround", &config));
+    EXPECT_EQ(android::ResTable_config::SCREENROUND_NO,
+              config.screenLayout2 & android::ResTable_config::MASK_SCREENROUND);
+    EXPECT_EQ(SDK_MNC, config.sdkVersion);
+    EXPECT_EQ(String8("notround-v23"), config.toString());
+}
diff --git a/tools/layoutlib/bridge/resources/bars/navigation_bar.xml b/tools/layoutlib/bridge/resources/bars/navigation_bar.xml
index 79920a1..55bd1d2 100644
--- a/tools/layoutlib/bridge/resources/bars/navigation_bar.xml
+++ b/tools/layoutlib/bridge/resources/bars/navigation_bar.xml
@@ -1,8 +1,25 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 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.
+  -->
+
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 	<View
 			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"/>
+			android:layout_height="wrap_content"
+			android:visibility="invisible"/>
 	<ImageView
 			android:layout_height="wrap_content"
 			android:layout_width="wrap_content"
@@ -10,20 +27,23 @@
 	<View
 			android:layout_height="wrap_content"
 			android:layout_width="wrap_content"
-			android:layout_weight="1"/>
+			android:layout_weight="1"
+			android:visibility="invisible"/>
 	<ImageView
 			android:layout_height="wrap_content"
 			android:layout_width="wrap_content"
 			android:scaleType="centerInside"/>
 	<View
-		android:layout_height="wrap_content"
-		android:layout_width="wrap_content"
-		android:layout_weight="1"/>
+			android:layout_height="wrap_content"
+			android:layout_width="wrap_content"
+			android:layout_weight="1"
+			android:visibility="invisible"/>
 	<ImageView
 			android:layout_height="wrap_content"
 			android:layout_width="wrap_content"
 			android:scaleType="centerInside"/>
 	<View
 			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"/>
+			android:layout_height="wrap_content"
+			android:visibility="invisible"/>
 </merge>
diff --git a/tools/layoutlib/bridge/resources/bars/navigation_bar600dp.xml b/tools/layoutlib/bridge/resources/bars/navigation_bar600dp.xml
new file mode 100644
index 0000000..e208a0d
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/navigation_bar600dp.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 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.
+  -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+	<View
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_weight="1"
+		  	android:visibility="invisible"/>
+	<ImageView
+			android:layout_height="wrap_content"
+			android:layout_width="wrap_content"
+			android:scaleType="centerInside"/>
+	<View
+			android:layout_height="wrap_content"
+			android:layout_width="wrap_content"
+			android:visibility="invisible"/>
+	<ImageView
+			android:layout_height="wrap_content"
+			android:layout_width="wrap_content"
+			android:scaleType="centerInside"/>
+	<View
+			android:layout_height="wrap_content"
+			android:layout_width="wrap_content"
+			android:visibility="invisible"/>
+	<ImageView
+			android:layout_height="wrap_content"
+			android:layout_width="wrap_content"
+			android:scaleType="centerInside"/>
+	<View
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_weight="1"
+			android:visibility="invisible"/>
+</merge>
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index 16f477b..dcf82a3 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -41,6 +41,9 @@
     private static final int WIDTH_DEFAULT = 36;
     private static final int WIDTH_SW360 = 40;
     private static final int WIDTH_SW600 = 48;
+    private static final String LAYOUT_XML = "/bars/navigation_bar.xml";
+    private static final String LAYOUT_600DP_XML = "/bars/navigation_bar600dp.xml";
+
 
     /**
      * Constructor to be used when creating the {@link NavigationBar} as a regular control.
@@ -59,8 +62,8 @@
 
     public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
             boolean rtlEnabled, int simulatedPlatformVersion) throws XmlPullParserException {
-        super(context, orientation, "/bars/navigation_bar.xml", "navigation_bar.xml",
-                simulatedPlatformVersion);
+        super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
+                "navigation_bar.xml", simulatedPlatformVersion);
 
         int color = getThemeAttrColor(ATTR_COLOR, true);
         setBackgroundColor(color == 0 ? 0xFF000000 : color);
@@ -87,13 +90,19 @@
     }
 
     private void setupNavBar(BridgeContext context, int orientation) {
+        float sw = getShortestWidth(context);
         View leftPadding = getChildAt(0);
         View rightPadding = getChildAt(6);
-        setSize(context, leftPadding, orientation, getSidePadding(context));
-        setSize(context, rightPadding, orientation, getSidePadding(context));
+        setSize(context, leftPadding, orientation, getSidePadding(sw));
+        setSize(context, rightPadding, orientation, getSidePadding(sw));
+        int navButtonWidth = getWidth(sw);
         for (int i = 1; i < 6; i += 2) {
             View navButton = getChildAt(i);
-            setSize(context, navButton, orientation, getWidth(context));
+            setSize(context, navButton, orientation, navButtonWidth);
+        }
+        if (sw >= 600) {
+            setSize(context, getChildAt(2), orientation, 128);
+            setSize(context, getChildAt(4), orientation, 128);
         }
     }
 
@@ -108,11 +117,7 @@
         view.setLayoutParams(layoutParams);
     }
 
-    private static int getSidePadding(BridgeContext context) {
-        DisplayMetrics metrics = context.getMetrics();
-        float sw = metrics.widthPixels > metrics.heightPixels
-                ? metrics.heightPixels : metrics.widthPixels;
-        sw /= metrics.density;
+    private static int getSidePadding(float sw) {
         if (sw >= 400) {
             return PADDING_WIDTH_SW400;
         }
@@ -122,11 +127,7 @@
         return PADDING_WIDTH_DEFAULT;
     }
 
-    private static int getWidth(BridgeContext context) {
-        DisplayMetrics metrics = context.getMetrics();
-        float sw = metrics.widthPixels > metrics.heightPixels
-                ? metrics.heightPixels : metrics.widthPixels;
-        sw /= metrics.density;
+    private static int getWidth(float sw) {
         if (sw >= 600) {
             return WIDTH_SW600;
         }
@@ -136,6 +137,14 @@
         return WIDTH_DEFAULT;
     }
 
+    private static float getShortestWidth(BridgeContext context) {
+        DisplayMetrics metrics = context.getMetrics();
+        float sw = metrics.widthPixels < metrics.heightPixels ?
+                metrics.widthPixels : metrics.heightPixels;
+        sw /= metrics.density;
+        return sw;
+    }
+
     @Override
     protected TextView getStyleableTextView() {
         return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 677c744..a3fde866 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.layoutlib.bridge.impl;
 
+import com.android.SdkConstants;
 import com.android.annotations.NonNull;
 import com.android.ide.common.rendering.api.DensityBasedResourceValue;
 import com.android.ide.common.rendering.api.LayoutLog;
@@ -70,6 +71,10 @@
     public static int getColor(String value) {
         if (value != null) {
             if (!value.startsWith("#")) {
+                if (value.startsWith(SdkConstants.PREFIX_THEME_REF)) {
+                    throw new NumberFormatException(String.format(
+                            "Attribute '%s' not found. Are you using the right theme?", value));
+                }
                 throw new NumberFormatException(
                         String.format("Color value '%s' must start with #", value));
             }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 00cdc71..b2af044 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -152,17 +152,20 @@
 
     int getVerboseLoggingLevel();
 
+    void enableAggressiveHandover(int enabled);
     int getAggressiveHandover();
 
-    void enableAggressiveHandover(int enabled);
-
+    void setAllowScansWithTraffic(int enabled);
     int getAllowScansWithTraffic();
 
-    void setAllowScansWithTraffic(int enabled);
+    void setAllowScansWhileAssociated(int enabled);
+    int getAllowScansWhileAssociated();
 
-    boolean getAllowScansWhileAssociated();
+    void setAllowNetworkSwitchingWhileAssociated(int enabled);
+    int getAllowNetworkSwitchingWhileAssociated();
 
-    void setAllowScansWhileAssociated(boolean enabled);
+    void setHalBasedAutojoinOffload(int enabled);
+    int getHalBasedAutojoinOffload();
 
     WifiConnectionStatistics getConnectionStatistics();
 
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 75198e5..dbfd4ef 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -42,6 +42,14 @@
     private static final EnumMap<SupplicantState, DetailedState> stateMap =
             new EnumMap<SupplicantState, DetailedState>(SupplicantState.class);
 
+    /**
+     * Default MAC address reported to a client that does not have the
+     * android.permission.LOCAL_MAC_ADDRESS permission.
+     *
+     * @hide
+     */
+    public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
+
     static {
         stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED);
         stateMap.put(SupplicantState.INTERFACE_DISABLED, DetailedState.DISCONNECTED);
@@ -91,7 +99,7 @@
     private int mFrequency;
 
     private InetAddress mIpAddress;
-    private String mMacAddress;
+    private String mMacAddress = DEFAULT_MAC_ADDRESS;
 
     /**
      * @hide
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index a2b1858..f2c2a28 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2773,7 +2773,7 @@
      * Set setting for allowing Scans when infrastructure is associated
      * @hide
      */
-    public void setAllowScansWhileAssociated(boolean enabled) {
+    public void setAllowScansWhileAssociated(int enabled) {
         try {
             mService.setAllowScansWhileAssociated(enabled);
         } catch (RemoteException e) {
@@ -2785,12 +2785,12 @@
      * Get setting for allowing Scans when infrastructure is associated
      * @hide
      */
-    public boolean getAllowScansWhileAssociated() {
+    public int getAllowScansWhileAssociated() {
         try {
             return mService.getAllowScansWhileAssociated();
         } catch (RemoteException e) {
         }
-        return false;
+        return 0;
     }
 
     /**
@@ -2817,4 +2817,52 @@
             return null;
         }
     }
+
+    /**
+     * Set setting for enabling autojoin Offload thru Wifi HAL layer
+     * @hide
+     */
+    public void setHalBasedAutojoinOffload(int enabled) {
+        try {
+            mService.setHalBasedAutojoinOffload(enabled);
+        } catch (RemoteException e) {
+
+        }
+    }
+
+    /**
+     * Get setting for enabling autojoin Offload thru Wifi HAL layer
+     * @hide
+     */
+    public int getHalBasedAutojoinOffload() {
+        try {
+            return mService.getHalBasedAutojoinOffload();
+        } catch (RemoteException e) {
+        }
+        return 0;
+    }
+
+    /**
+     * Set setting for enabling network switching while wifi is associated
+     * @hide
+     */
+    public void setAllowNetworkSwitchingWhileAssociated(int enabled) {
+        try {
+            mService.setAllowNetworkSwitchingWhileAssociated(enabled);
+        } catch (RemoteException e) {
+
+        }
+    }
+
+    /**
+     * Get setting for enabling network switching while wifi is associated
+     * @hide
+     */
+    public int getAllowNetworkSwitchingWhileAssociated() {
+        try {
+            return mService.getAllowNetworkSwitchingWhileAssociated();
+        } catch (RemoteException e) {
+        }
+        return 0;
+    }
 }