Merge "[AWARE] Remove Publish/Subscribe Count configuration" am: 5d81b9d67d am: 9bc8e05da2 am: 342a27e7f7
am: b36a9e0eb5

Change-Id: I0c4f93b03a73e169da7250b1cf7e5cc1269d4f07
diff --git a/api/current.txt b/api/current.txt
index 2ed183e..e4720d2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41077,9 +41077,9 @@
   public static final class FontConfig.Font implements android.os.Parcelable {
     method public int describeContents();
     method public android.text.FontConfig.Axis[] getAxes();
-    method public android.os.ParcelFileDescriptor getFd();
     method public java.lang.String getFontName();
     method public int getTtcIndex();
+    method public android.net.Uri getUri();
     method public int getWeight();
     method public boolean isItalic();
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 9718b9b..0588855 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -44531,9 +44531,9 @@
   public static final class FontConfig.Font implements android.os.Parcelable {
     method public int describeContents();
     method public android.text.FontConfig.Axis[] getAxes();
-    method public android.os.ParcelFileDescriptor getFd();
     method public java.lang.String getFontName();
     method public int getTtcIndex();
+    method public android.net.Uri getUri();
     method public int getWeight();
     method public boolean isItalic();
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index cfbb7be..dc72d73 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -41284,9 +41284,9 @@
   public static final class FontConfig.Font implements android.os.Parcelable {
     method public int describeContents();
     method public android.text.FontConfig.Axis[] getAxes();
-    method public android.os.ParcelFileDescriptor getFd();
     method public java.lang.String getFontName();
     method public int getTtcIndex();
+    method public android.net.Uri getUri();
     method public int getWeight();
     method public boolean isItalic();
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index bace226..147b5d0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2740,6 +2740,10 @@
                 return true;
             }
             return false;
+        } else if (keyCode == KeyEvent.KEYCODE_TAB) {
+            // Don't consume TAB here since it's used for navigation. Arrow keys
+            // aren't considered "typing keys" so they already won't get consumed.
+            return false;
         } else {
             // Common code for DEFAULT_KEYS_DIALER & DEFAULT_KEYS_SEARCH_*
             boolean clearSpannable = false;
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
index 8a316f1..3665d1b 100644
--- a/core/java/android/companion/BluetoothDeviceFilterUtils.java
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -37,7 +37,7 @@
     private BluetoothDeviceFilterUtils() {}
 
     private static final boolean DEBUG = false;
-    private static final String LOG_TAG = "BluetoothDeviceFilterUtil";
+    private static final String LOG_TAG = "BluetoothDeviceFilterUtils";
 
     @Nullable
     static String patternToString(@Nullable Pattern p) {
@@ -50,8 +50,10 @@
     }
 
     static boolean matches(ScanFilter filter, BluetoothDevice device) {
-        return matchesAddress(filter.getDeviceAddress(), device)
+        boolean result = matchesAddress(filter.getDeviceAddress(), device)
                 && matchesServiceUuid(filter.getServiceUuid(), filter.getServiceUuidMask(), device);
+        if (DEBUG) debugLogMatchResult(result, device, filter);
+        return result;
     }
 
     static boolean matchesAddress(String deviceAddress, BluetoothDevice device) {
diff --git a/core/java/android/companion/BluetoothLEDeviceFilter.java b/core/java/android/companion/BluetoothLEDeviceFilter.java
index 0444775..5a1b29d 100644
--- a/core/java/android/companion/BluetoothLEDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLEDeviceFilter.java
@@ -31,6 +31,7 @@
 import android.os.Parcel;
 import android.provider.OneTimeUseBuilder;
 import android.text.TextUtils;
+import android.util.Log;
 
 import com.android.internal.util.BitUtils;
 import com.android.internal.util.ObjectUtils;
@@ -47,6 +48,9 @@
  */
 public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> {
 
+    private static final boolean DEBUG = false;
+    private static final String LOG_TAG = "BluetoothLEDeviceFilter";
+
     private static final int RENAME_PREFIX_LENGTH_LIMIT = 10;
 
     private final Pattern mNamePattern;
@@ -145,9 +149,13 @@
     /** @hide */
     @Override
     public boolean matches(ScanResult device) {
-        return matches(device.getDevice())
-                && BitUtils.maskedEquals(device.getScanRecord().getBytes(),
-                        mRawDataFilter, mRawDataFilterMask);
+        boolean result = matches(device.getDevice())
+                && (mRawDataFilter == null
+                    || BitUtils.maskedEquals(device.getScanRecord().getBytes(),
+                            mRawDataFilter, mRawDataFilterMask));
+        if (DEBUG) Log.i(LOG_TAG, "matches(this = " + this + ", device = " + device +
+                ") -> " + result);
+        return result;
     }
 
     private boolean matches(BluetoothDevice device) {
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index dbe1394..00e047d 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1112,6 +1112,8 @@
                 return ImageFormat.DEPTH_POINT_CLOUD;
             case HAL_PIXEL_FORMAT_Y16:
                 return ImageFormat.DEPTH16;
+            case HAL_PIXEL_FORMAT_RAW16:
+                return ImageFormat.RAW_DEPTH;
             case ImageFormat.JPEG:
                 throw new IllegalArgumentException(
                         "ImageFormat.JPEG is an unknown internal format");
@@ -1179,6 +1181,8 @@
                 return HAL_PIXEL_FORMAT_BLOB;
             case ImageFormat.DEPTH16:
                 return HAL_PIXEL_FORMAT_Y16;
+            case ImageFormat.RAW_DEPTH:
+                return HAL_PIXEL_FORMAT_RAW16;
             default:
                 return format;
         }
@@ -1220,6 +1224,7 @@
                 return HAL_DATASPACE_V0_JFIF;
             case ImageFormat.DEPTH_POINT_CLOUD:
             case ImageFormat.DEPTH16:
+            case ImageFormat.RAW_DEPTH:
                 return HAL_DATASPACE_DEPTH;
             default:
                 return HAL_DATASPACE_UNKNOWN;
@@ -1609,6 +1614,8 @@
                 return "DEPTH16";
             case ImageFormat.DEPTH_POINT_CLOUD:
                 return "DEPTH_POINT_CLOUD";
+            case ImageFormat.RAW_DEPTH:
+                return "RAW_DEPTH";
             case ImageFormat.PRIVATE:
                 return "PRIVATE";
             default:
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index 14bb923..58c3d24 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -196,6 +196,19 @@
             return mIsCaptureSupported;
         }
 
+        /**
+         * {@code true} if the module supports background scanning. At the given time it may not
+         * be available though, see {@link RadioTuner#startBackgroundScan()}.
+         *
+         * @return {@code true} if background scanning is supported (not necessary available
+         * at a given time), {@code false} otherwise.
+         *
+         * @hide FutureFeature
+         */
+        public boolean isBackgroundScanningSupported() {
+            return false;
+        }
+
         /** List of descriptors for all bands supported by this module.
          * @return an array of {@link BandDescriptor}.
          */
diff --git a/core/java/android/hardware/radio/RadioModule.java b/core/java/android/hardware/radio/RadioModule.java
index 8964893..033403a 100644
--- a/core/java/android/hardware/radio/RadioModule.java
+++ b/core/java/android/hardware/radio/RadioModule.java
@@ -79,6 +79,8 @@
 
     public native int getProgramInformation(RadioManager.ProgramInfo[] info);
 
+    public native boolean startBackgroundScan();
+
     public native @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter);
 
     public native boolean isAntennaConnected();
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index c8034eb..1159d7d 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -212,6 +212,23 @@
     public abstract int getProgramInformation(RadioManager.ProgramInfo[] info);
 
     /**
+     * Initiates a background scan to update internally cached program list.
+     *
+     * It may not be necessary to initiate the scan explicitly - the scan MAY be performed on boot.
+     *
+     * The operation is asynchronous and {@link Callback} backgroundScanComplete or onError will
+     * be called if the return value of this call was {@code true}. As result of this call
+     * programListChanged may be triggered (if the scanned list differs).
+     *
+     * @return {@code true} if the scan was properly scheduled, {@code false} if the scan feature
+     * is unavailable; ie. temporarily due to ongoing foreground playback in single-tuner device
+     * or permanently if the feature is not supported
+     * (see ModuleProperties#isBackgroundScanningSupported()).
+     * @hide FutureFeature
+     */
+    public abstract boolean startBackgroundScan();
+
+    /**
      * Get the list of discovered radio stations.
      *
      * To get the full list, set filter to null or empty string. Otherwise, client application
@@ -219,7 +236,8 @@
      *
      * @param filter vendor-specific selector for radio stations.
      * @return a list of radio stations.
-     * @throws IllegalStateException if the scan is in progress or has not been started.
+     * @throws IllegalStateException if the scan is in progress or has not been started,
+     *         startBackgroundScan() call may fix it.
      * @throws IllegalArgumentException if the filter argument is not valid.
      * @hide FutureFeature
      */
@@ -317,6 +335,32 @@
          * with control set to {@code true}.
          */
         public void onControlChanged(boolean control) {}
+
+        /**
+         * onBackgroundScanAvailabilityChange() is called when background scan
+         * feature becomes available or not.
+         *
+         * @param isAvailable true, if the tuner turned temporarily background-
+         *                    capable, false in the other case.
+         * @hide FutureFeature
+         */
+        public void onBackgroundScanAvailabilityChange(boolean isAvailable) {}
+
+        /**
+         * Called when a background scan completes successfully.
+         *
+         * @hide FutureFeature
+         */
+        public void onBackgroundScanComplete() {}
+
+        /**
+         * Called when available program list changed.
+         *
+         * Use getProgramList() to get the actual list.
+         *
+         * @hide FutureFeature
+         */
+        public void onProgramListChanged() {}
     }
 
 }
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 70f9bdd..14d3ad7 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -22,13 +22,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.FontListParser;
+import android.net.Uri;
 import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 
-import java.io.IOException;
 import java.lang.annotation.Retention;
-import java.util.Arrays;
 
 
 /**
@@ -44,20 +42,6 @@
     }
 
     /**
-     * For duplicating file descriptors.
-     *
-     * Note that this copy constructor can not be usable for deep copy.
-     * @hide
-     */
-    public FontConfig(@NonNull FontConfig config) {
-        mFamilies = new Family[config.mFamilies.length];
-        for (int i = 0; i < config.mFamilies.length; ++i) {
-            mFamilies[i] = new Family(config.mFamilies[i]);
-        }
-        mAliases = Arrays.copyOf(config.mAliases, config.mAliases.length);
-    }
-
-    /**
      * Returns the ordered list of families included in the system fonts.
      */
     public @NonNull Family[] getFamilies() {
@@ -174,7 +158,7 @@
         private final @NonNull Axis[] mAxes;
         private final int mWeight;
         private final boolean mIsItalic;
-        private @Nullable ParcelFileDescriptor mFd;
+        private Uri mUri;
 
         /**
          * @hide
@@ -186,29 +170,6 @@
             mAxes = axes;
             mWeight = weight;
             mIsItalic = isItalic;
-            mFd = null;
-        }
-
-        /**
-         * This is for duplicating FileDescriptors.
-         *
-         * Note that this copy ctor doesn't deep copy the members.
-         *
-         * @hide
-         */
-        public Font(Font origin) {
-            mFontName = origin.mFontName;
-            mTtcIndex = origin.mTtcIndex;
-            mAxes = origin.mAxes;
-            mWeight = origin.mWeight;
-            mIsItalic = origin.mIsItalic;
-            if (origin.mFd != null) {
-                try {
-                    mFd = origin.mFd.dup();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
         }
 
         /**
@@ -247,17 +208,20 @@
         }
 
         /**
-         * Returns a file descriptor to access the specified font. This should be closed after use.
+         * Returns the content uri associated to this font.
+         *
+         * You can reach to the font contents by calling {@link
+         * android.content.ContentResolver#openInputStream}.
          */
-        public @Nullable ParcelFileDescriptor getFd() {
-            return mFd;
+        public @Nullable Uri getUri() {
+            return mUri;
         }
 
         /**
          * @hide
          */
-        public void setFd(@NonNull ParcelFileDescriptor fd) {
-            mFd = fd;
+        public void setUri(@NonNull Uri uri) {
+            mUri = uri;
         }
 
         /**
@@ -269,11 +233,7 @@
             mAxes = in.createTypedArray(Axis.CREATOR);
             mWeight = in.readInt();
             mIsItalic = in.readInt() == 1;
-            if (in.readInt() == 1) { /* has FD */
-                mFd = ParcelFileDescriptor.CREATOR.createFromParcel(in);
-            } else {
-                mFd = null;
-            }
+            mUri = in.readTypedObject(Uri.CREATOR);
         }
 
         @Override
@@ -283,10 +243,7 @@
             out.writeTypedArray(mAxes, flag);
             out.writeInt(mWeight);
             out.writeInt(mIsItalic ? 1 : 0);
-            out.writeInt(mFd == null ? 0 : 1);
-            if (mFd != null) {
-                mFd.writeToParcel(out, flag);
-            }
+            out.writeTypedObject(mUri, flag);
         }
 
         @Override
@@ -425,22 +382,6 @@
         }
 
         /**
-         * For duplicating file descriptor underlying Font object.
-         *
-         * This copy constructor is not for deep copying.
-         * @hide
-         */
-        public Family(Family origin) {
-            mName = origin.mName;
-            mLanguage = origin.mLanguage;
-            mVariant = origin.mVariant;
-            mFonts = new Font[origin.mFonts.length];
-            for (int i = 0; i < origin.mFonts.length; ++i) {
-                mFonts[i] = new Font(origin.mFonts[i]);
-            }
-        }
-
-        /**
          * Returns the name given by the system to this font family.
          */
         public @Nullable String getName() {
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 61c9201..ae1ee42 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.PackageManager;
 import android.graphics.Rect;
 import android.util.ArrayMap;
 import android.util.SparseArray;
@@ -88,8 +89,9 @@
 
     private View findNextFocus(ViewGroup root, View focused, Rect focusedRect, int direction) {
         View next = null;
+        ViewGroup effectiveRoot = getEffectiveRoot(root, focused);
         if (focused != null) {
-            next = findNextUserSpecifiedFocus(root, focused, direction);
+            next = findNextUserSpecifiedFocus(effectiveRoot, focused, direction);
         }
         if (next != null) {
             return next;
@@ -97,9 +99,9 @@
         ArrayList<View> focusables = mTempList;
         try {
             focusables.clear();
-            root.addFocusables(focusables, direction);
+            effectiveRoot.addFocusables(focusables, direction);
             if (!focusables.isEmpty()) {
-                next = findNextFocus(root, focused, focusedRect, direction, focusables);
+                next = findNextFocus(effectiveRoot, focused, focusedRect, direction, focusables);
             }
         } finally {
             focusables.clear();
@@ -108,6 +110,35 @@
     }
 
     /**
+     * Returns the "effective" root of a view. The "effective" root is the closest ancestor
+     * within-which focus should cycle.
+     * <p>
+     * For example: normal focus navigation would stay within a ViewGroup marked as
+     * touchscreenBlocksFocus and keyboardNavigationCluster until a cluster-jump out.
+     * @return the "effective" root of {@param focused}
+     */
+    private ViewGroup getEffectiveRoot(ViewGroup root, View focused) {
+        if (focused == null) {
+            return root;
+        }
+        ViewParent effective = focused.getParent();
+        do {
+            if (effective == root) {
+                return root;
+            }
+            ViewGroup vg = (ViewGroup) effective;
+            if (vg.getTouchscreenBlocksFocus()
+                    && focused.getContext().getPackageManager().hasSystemFeature(
+                            PackageManager.FEATURE_TOUCHSCREEN)
+                    && vg.isKeyboardNavigationCluster()) {
+                return vg;
+            }
+            effective = effective.getParent();
+        } while (effective != null);
+        return root;
+    }
+
+    /**
      * Find the root of the next keyboard navigation cluster after the current one.
      * @param root The view tree to look inside. Cannot be null
      * @param currentCluster The starting point of the search. Null means the default cluster
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3f52a9d..e924f77 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -61,6 +61,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManagerGlobal;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -4170,14 +4171,14 @@
     /**
      * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to
      * request read access to the content URI(s) contained in the {@link ClipData} object.
-     * @see android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION
+     * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION
      */
     public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION;
 
     /**
      * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to
      * request write access to the content URI(s) contained in the {@link ClipData} object.
-     * @see android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+     * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION
      */
     public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
 
@@ -4185,8 +4186,8 @@
      * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link
      * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device
      * reboots until explicitly revoked with
-     * {@link android.content.Context#revokeUriPermission(Uri,int) Context.revokeUriPermission}.
-     * @see android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+     * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}.
+     * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION
      */
     public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION =
             Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
@@ -4195,7 +4196,7 @@
      * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link
      * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix
      * match against the original granted URI.
-     * @see android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
+     * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION
      */
     public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION =
             Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
@@ -7895,7 +7896,7 @@
      * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be
      *                  {@code null} if the service provided no arguments.
      *
-     * @see AccessibilityNodeInfo#setExtraAvailableData
+     * @see AccessibilityNodeInfo#setAvailableExtraData(List)
      */
     public void addExtraDataToAccessibilityNodeInfo(
             @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey,
@@ -9839,7 +9840,7 @@
      * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
      * window or serves as a target of cluster navigation.
      *
-     * @see #restoreDefaultFocus(int)
+     * @see #restoreDefaultFocus()
      *
      * @return {@code true} if this view is the default-focus view, {@code false} otherwise
      * @attr ref android.R.styleable#View_focusedByDefault
@@ -9859,7 +9860,7 @@
      * @param isFocusedByDefault {@code true} to set this view as the default-focus view,
      *                           {@code false} otherwise.
      *
-     * @see #restoreDefaultFocus(int)
+     * @see #restoreDefaultFocus()
      *
      * @attr ref android.R.styleable#View_focusedByDefault
      */
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7921938..c250226 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1190,7 +1190,8 @@
         final int focusableCount = views.size();
 
         final int descendantFocusability = getDescendantFocusability();
-        final boolean focusSelf = (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen());
+        final boolean blockFocusForTouchscreen = shouldBlockFocusForTouchscreen();
+        final boolean focusSelf = (isFocusableInTouchMode() || !blockFocusForTouchscreen);
 
         if (descendantFocusability == FOCUS_BLOCK_DESCENDANTS) {
             if (focusSelf) {
@@ -1199,7 +1200,7 @@
             return;
         }
 
-        if (shouldBlockFocusForTouchscreen()) {
+        if (blockFocusForTouchscreen) {
             focusableMode |= FOCUSABLES_TOUCH_MODE;
         }
 
@@ -1234,7 +1235,19 @@
     public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
         final int focusableCount = views.size();
 
-        super.addKeyboardNavigationClusters(views, direction);
+        if (isKeyboardNavigationCluster()) {
+            // Cluster-navigation can enter a touchscreenBlocksFocus cluster, so temporarily
+            // disable touchscreenBlocksFocus to evaluate whether it contains focusables.
+            final boolean blockedFocus = getTouchscreenBlocksFocus();
+            try {
+                setTouchscreenBlocksFocusNoRefocus(false);
+                super.addKeyboardNavigationClusters(views, direction);
+            } finally {
+                setTouchscreenBlocksFocusNoRefocus(blockedFocus);
+            }
+        } else {
+            super.addKeyboardNavigationClusters(views, direction);
+        }
 
         if (focusableCount != views.size()) {
             // No need to look for groups inside a group.
@@ -1280,6 +1293,14 @@
         }
     }
 
+    private void setTouchscreenBlocksFocusNoRefocus(boolean touchscreenBlocksFocus) {
+        if (touchscreenBlocksFocus) {
+            mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
+        } else {
+            mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
+        }
+    }
+
     /**
      * Check whether this ViewGroup should ignore focus requests for itself and its children.
      */
@@ -1288,8 +1309,12 @@
     }
 
     boolean shouldBlockFocusForTouchscreen() {
+        // There is a special case for keyboard-navigation clusters. We allow cluster navigation
+        // to jump into blockFocusForTouchscreen ViewGroups which are clusters. Once in the
+        // cluster, focus is free to move around within it.
         return getTouchscreenBlocksFocus() &&
-                mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
+                mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
+                && (!hasFocus() || !isKeyboardNavigationCluster());
     }
 
     @Override
@@ -3175,6 +3200,21 @@
     @TestApi
     @Override
     public boolean restoreFocusInCluster(@FocusRealDirection int direction) {
+        // Allow cluster-navigation to enter touchscreenBlocksFocus ViewGroups.
+        if (isKeyboardNavigationCluster()) {
+            final boolean blockedFocus = getTouchscreenBlocksFocus();
+            try {
+                setTouchscreenBlocksFocusNoRefocus(false);
+                return restoreFocusInClusterInternal(direction);
+            } finally {
+                setTouchscreenBlocksFocusNoRefocus(blockedFocus);
+            }
+        } else {
+            return restoreFocusInClusterInternal(direction);
+        }
+    }
+
+    private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) {
         if (mFocusedInCluster != null && !mFocusedInCluster.isKeyboardNavigationCluster()
                 && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
                 && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 1937187..99b91bd 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -6873,9 +6873,11 @@
                     mTransientStateViews.put(position, scrap);
                 } else {
                     // Otherwise, we'll have to remove the view and start over.
+                    clearScrapForRebind(scrap);
                     getSkippedScrap().add(scrap);
                 }
             } else {
+                clearScrapForRebind(scrap);
                 if (mViewTypeCount == 1) {
                     mCurrentScrap.add(scrap);
                 } else {
@@ -7098,12 +7100,12 @@
                         }
                     } else if (params.scrappedFromPosition == position) {
                         final View scrap = scrapViews.remove(i);
-                        clearAccessibilityFromScrap(scrap);
+                        clearScrapForRebind(scrap);
                         return scrap;
                     }
                 }
                 final View scrap = scrapViews.remove(size - 1);
-                clearAccessibilityFromScrap(scrap);
+                clearScrapForRebind(scrap);
                 return scrap;
             } else {
                 return null;
@@ -7117,7 +7119,7 @@
             }
         }
 
-        private void clearAccessibilityFromScrap(View view) {
+        private void clearScrapForRebind(View view) {
             view.clearAccessibilityFocus();
             view.setAccessibilityDelegate(null);
         }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 1c0c4ef..12e35a1 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1639,7 +1639,7 @@
                     final View focusChild = getAccessibilityFocusedChild(focusHost);
                     if (focusChild != null) {
                         if (!dataChanged || isDirectChildHeaderOrFooter(focusChild)
-                                || focusChild.hasTransientState() || mAdapterHasStableIds) {
+                                || (focusChild.hasTransientState() && mAdapterHasStableIds)) {
                             // The views won't be changing, so try to maintain
                             // focus on the current host and virtual view.
                             accessibilityFocusLayoutRestoreView = focusHost;
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 2eb50e0..bf3085d 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -343,6 +343,9 @@
             final ViewGroup vgParent = (ViewGroup) parent;
             if (vgParent.isKeyboardNavigationCluster()) {
                 setKeyboardNavigationCluster(false);
+                if (vgParent.getTouchscreenBlocksFocus()) {
+                    setTouchscreenBlocksFocus(false);
+                }
                 break;
             }
             parent = vgParent.getParent();
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 7ce5fc3..b3904f4 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -477,12 +477,9 @@
             final KeyCharacterMap kmap = KeyCharacterMap.load(
                     event != null ? event.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD);
             menu.setQwertyMode(kmap.getKeyboardType() != KeyCharacterMap.NUMERIC);
-            menu.performShortcut(keyCode, event, 0);
+            return menu.performShortcut(keyCode, event, 0);
         }
-        // This action bar always returns true for handling keyboard shortcuts.
-        // This will block the window from preparing a temporary panel to handle
-        // keyboard shortcuts.
-        return true;
+        return false;
     }
 
     @Override
@@ -525,6 +522,17 @@
             }
             return result;
         }
+
+        @Override
+        public View onCreatePanelView(int featureId) {
+            if (featureId == Window.FEATURE_OPTIONS_PANEL) {
+                // This gets called by PhoneWindow.preparePanel. Since this already manages
+                // its own panel, we return a dummy view here to prevent PhoneWindow from
+                // preparing a default one.
+                return new View(mDecorToolbar.getContext());
+            }
+            return super.onCreatePanelView(featureId);
+        }
     }
 
     private final class ActionMenuPresenterCallback implements MenuPresenter.Callback {
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 713287e..8a7d1cf 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -135,6 +135,7 @@
         case PublicFormat::DEPTH16:
             return HAL_PIXEL_FORMAT_Y16;
         case PublicFormat::RAW_SENSOR:
+        case PublicFormat::RAW_DEPTH:
             return HAL_PIXEL_FORMAT_RAW16;
         default:
             // Most formats map 1:1
@@ -149,6 +150,7 @@
             return HAL_DATASPACE_V0_JFIF;
         case PublicFormat::DEPTH_POINT_CLOUD:
         case PublicFormat::DEPTH16:
+        case PublicFormat::RAW_DEPTH:
             return HAL_DATASPACE_DEPTH;
         case PublicFormat::RAW_SENSOR:
         case PublicFormat::RAW_PRIVATE:
@@ -182,8 +184,12 @@
             // Enums overlap in both name and value
             return static_cast<PublicFormat>(format);
         case HAL_PIXEL_FORMAT_RAW16:
-            // Name differs, though value is the same
-            return PublicFormat::RAW_SENSOR;
+            switch (dataSpace) {
+                case HAL_DATASPACE_DEPTH:
+                  return PublicFormat::RAW_DEPTH;
+                default:
+                  return PublicFormat::RAW_SENSOR;
+            }
         case HAL_PIXEL_FORMAT_RAW_OPAQUE:
             // Name differs, though value is the same
             return PublicFormat::RAW_PRIVATE;
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 6fbf49b..066ce68 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -167,7 +167,7 @@
             buffer->getHeight(),
             buffer->getPixelFormat(),
             buffer->getUsage(),
-            (void*)buffer.get());
+            (jlong)buffer.get());
 }
 
 static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
diff --git a/core/jni/include/android_runtime/android_view_Surface.h b/core/jni/include/android_runtime/android_view_Surface.h
index 3f1bdff..d27c5a3 100644
--- a/core/jni/include/android_runtime/android_view_Surface.h
+++ b/core/jni/include/android_runtime/android_view_Surface.h
@@ -53,6 +53,7 @@
     RGBA_1010102      = 0x2b,
     JPEG              = 0x100,
     DEPTH_POINT_CLOUD = 0x101,
+    RAW_DEPTH         = 0x1002, // @hide
     YV12              = 0x32315659,
     Y8                = 0x20203859, // @hide
     Y16               = 0x20363159, // @hide
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index edcbb2b..4c1d6cb 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -35,6 +35,7 @@
         android:layout_alignParentTop="true"
         style="?attr/actionBarStyle"
         android:transitionName="android:action_bar"
+        android:touchscreenBlocksFocus="true"
         android:keyboardNavigationCluster="true"
         android:gravity="top">
         <com.android.internal.widget.ActionBarView
@@ -54,6 +55,7 @@
                   android:layout_height="wrap_content"
                   style="?attr/actionBarSplitStyle"
                   android:visibility="gone"
+                  android:touchscreenBlocksFocus="true"
                   android:keyboardNavigationCluster="true"
                   android:gravity="center"/>
 </com.android.internal.widget.ActionBarOverlayLayout>
diff --git a/core/res/res/layout/screen_toolbar.xml b/core/res/res/layout/screen_toolbar.xml
index 0bec8c4..ded2527 100644
--- a/core/res/res/layout/screen_toolbar.xml
+++ b/core/res/res/layout/screen_toolbar.xml
@@ -35,6 +35,7 @@
         android:layout_alignParentTop="true"
         style="?attr/actionBarStyle"
         android:transitionName="android:action_bar"
+        android:touchscreenBlocksFocus="true"
         android:keyboardNavigationCluster="true"
         android:gravity="top">
         <Toolbar
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 25873d2..7dac18d 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1249,6 +1249,7 @@
         <item name="collapseContentDescription">@string/toolbar_collapse_description</item>
         <item name="contentInsetStart">16dp</item>
         <item name="contentInsetStartWithNavigation">@dimen/action_bar_content_inset_with_nav</item>
+        <item name="touchscreenBlocksFocus">true</item>
         <item name="keyboardNavigationCluster">true</item>
     </style>
 
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index b78df34..ff9f11d 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -189,9 +189,8 @@
                 skip(parser);
             }
         }
-        String fullFilename = "/system/fonts/" +
-                FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
-        return new FontConfig.Font(fullFilename, index,
+        String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
+        return new FontConfig.Font(sanitizedName, index,
                 axes.toArray(new FontConfig.Axis[axes.size()]), weight, isItalic);
     }
 
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index a226e85..e3527e3 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -662,6 +662,15 @@
     public static final int DEPTH_POINT_CLOUD = 0x101;
 
     /**
+     * Unprocessed implementation-dependent raw
+     * depth measurements, opaque with 16 bit
+     * samples.
+     *
+     * @hide
+     */
+    public static final int RAW_DEPTH = 0x1002;
+
+    /**
      * Android private opaque image format.
      * <p>
      * The choices of the actual format and pixel data layout are entirely up to
@@ -723,6 +732,7 @@
                 return 24;
             case FLEX_RGBA_8888:
                 return 32;
+            case RAW_DEPTH:
             case RAW_SENSOR:
                 return 16;
             case RAW10:
@@ -765,6 +775,7 @@
             case DEPTH16:
             case DEPTH_POINT_CLOUD:
             case PRIVATE:
+            case RAW_DEPTH:
                 return true;
         }
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 228d950..8c3a2e8 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1003,21 +1003,22 @@
             Map<String, ByteBuffer> bufferForPath) {
         FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
         for (FontConfig.Font font : family.getFonts()) {
-            ByteBuffer fontBuffer = bufferForPath.get(font.getFontName());
+            String fullPathName = "/system/fonts/" + font.getFontName();
+            ByteBuffer fontBuffer = bufferForPath.get(fullPathName);
             if (fontBuffer == null) {
-                try (FileInputStream file = new FileInputStream(font.getFontName())) {
+                try (FileInputStream file = new FileInputStream(fullPathName)) {
                     FileChannel fileChannel = file.getChannel();
                     long fontSize = fileChannel.size();
                     fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
-                    bufferForPath.put(font.getFontName(), fontBuffer);
+                    bufferForPath.put(fullPathName, fontBuffer);
                 } catch (IOException e) {
-                    Log.e(TAG, "Error mapping font file " + font.getFontName());
+                    Log.e(TAG, "Error mapping font file " + fullPathName);
                     continue;
                 }
             }
             if (!fontFamily.addFontFromBuffer(fontBuffer, font.getTtcIndex(), font.getAxes(),
                     font.getWeight(), font.isItalic() ? Builder.ITALIC : Builder.NORMAL)) {
-                Log.e(TAG, "Error creating font " + font.getFontName() + "#" + font.getTtcIndex());
+                Log.e(TAG, "Error creating font " + fullPathName + "#" + font.getTtcIndex());
             }
         }
         fontFamily.freeze();
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 8823a92..f6b2912 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -491,6 +491,36 @@
     return *mCache.bitmap;
 }
 
+void Tree::updateCache(sk_sp<SkSurface> surface) {
+    if (surface.get()) {
+        mCache.surface = surface;
+    }
+    if (surface.get() || mCache.dirty) {
+        SkSurface* vdSurface = mCache.surface.get();
+        SkCanvas* canvas = vdSurface->getCanvas();
+        float scaleX = vdSurface->width() / mProperties.getViewportWidth();
+        float scaleY = vdSurface->height() / mProperties.getViewportHeight();
+        SkAutoCanvasRestore acr(canvas, true);
+        canvas->clear(SK_ColorTRANSPARENT);
+        canvas->scale(scaleX, scaleY);
+        mRootNode->draw(canvas, false);
+        mCache.dirty = false;
+        canvas->flush();
+    }
+}
+
+void Tree::draw(SkCanvas* canvas) {
+   /*
+    * TODO address the following...
+    *
+    * 1) figure out how to set path's as volatile during animation
+    * 2) if mRoot->getPaint() != null either promote to layer (during
+    *    animation) or cache in SkSurface (for static content)
+    */
+    canvas->drawImageRect(mCache.surface->makeImageSnapshot().get(),
+        mutateProperties()->getBounds(), getPaint());
+}
+
 void Tree::updateBitmapCache(Bitmap& bitmap, bool useStagingData) {
     SkBitmap outCache;
     bitmap.getSkBitmap(&outCache);
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 729a4dd..22cfe29 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -31,6 +31,7 @@
 #include <SkPathMeasure.h>
 #include <SkRect.h>
 #include <SkShader.h>
+#include <SkSurface.h>
 
 #include <cutils/compiler.h>
 #include <stddef.h>
@@ -677,15 +678,37 @@
     // This should only be called from animations on RT
     TreeProperties* mutateProperties() { return &mProperties; }
 
+    // called from RT only
+    const TreeProperties& properties() const { return mProperties; }
+
     // This should always be called from RT.
     void markDirty() { mCache.dirty = true; }
     bool isDirty() const { return mCache.dirty; }
     bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
     void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
 
+    // Returns true if VD cache surface is big enough. This should always be called from RT and it
+    // works with Skia pipelines only.
+    bool canReuseSurface() {
+        SkSurface* surface = mCache.surface.get();
+        return surface && surface->width() >= mProperties.getScaledWidth()
+              && surface->height() >= mProperties.getScaledHeight();
+    }
+
+    // Draws VD cache into a canvas. This should always be called from RT and it works with Skia
+    // pipelines only.
+    void draw(SkCanvas* canvas);
+
+    // Draws VD into a GPU backed surface. If canReuseSurface returns false, then "surface" must
+    // contain a new surface. This should always be called from RT and it works with Skia pipelines
+    // only.
+    void updateCache(sk_sp<SkSurface> surface);
+
 private:
     struct Cache {
-        sk_sp<Bitmap> bitmap;
+        sk_sp<Bitmap> bitmap; //used by HWUI pipeline and software
+        //TODO: use surface instead of bitmap when drawing in software canvas
+        sk_sp<SkSurface> surface; //used only by Skia pipelines
         bool dirty = true;
     };
 
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index 496f7ba..3ddc09f 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -19,6 +19,7 @@
 #include "renderthread/CanvasContext.h"
 #include "VectorDrawable.h"
 #include "DumpOpsCanvas.h"
+#include "SkiaPipeline.h"
 
 #include <SkImagePriv.h>
 
@@ -92,6 +93,8 @@
         // If any vector drawable in the display list needs update, damage the node.
         if (vectorDrawable->isDirty()) {
             isDirty = true;
+            static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline())
+                ->getVectorDrawables()->push_back(vectorDrawable);
         }
         vectorDrawable->setPropertyChangeWillBeConsumed(true);
     }
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 10c1865..75f1adc 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -25,6 +25,7 @@
 #include <SkPictureRecorder.h>
 #include <SkPixelSerializer.h>
 #include <SkStream.h>
+#include "VectorDrawable.h"
 
 #include <unistd.h>
 
@@ -40,7 +41,9 @@
 
 Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};
 
-SkiaPipeline::SkiaPipeline(RenderThread& thread) :  mRenderThread(thread) { }
+SkiaPipeline::SkiaPipeline(RenderThread& thread) :  mRenderThread(thread) {
+    mVectorDrawables.reserve(30);
+}
 
 TaskManager* SkiaPipeline::getTaskManager() {
     return &mTaskManager;
@@ -74,6 +77,7 @@
         const BakedOpRenderer::LightInfo& lightInfo) {
     updateLighting(lightGeometry, lightInfo);
     ATRACE_NAME("draw layers");
+    renderVectorDrawableCache();
     renderLayersImpl(*layerUpdateQueue, opaque);
     layerUpdateQueue->clear();
 }
@@ -176,10 +180,35 @@
     }
 };
 
+void SkiaPipeline::renderVectorDrawableCache() {
+    //render VectorDrawables into offscreen buffers
+    for (auto vd : mVectorDrawables) {
+        sk_sp<SkSurface> surface;
+        if (!vd->canReuseSurface()) {
+#ifndef ANDROID_ENABLE_LINEAR_BLENDING
+            sk_sp<SkColorSpace> colorSpace = nullptr;
+#else
+            sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
+#endif
+            int scaledWidth = SkScalarCeilToInt(vd->properties().getScaledWidth());
+            int scaledHeight = SkScalarCeilToInt(vd->properties().getScaledHeight());
+            SkImageInfo info = SkImageInfo::MakeN32(scaledWidth, scaledHeight,
+                    kPremul_SkAlphaType, colorSpace);
+            SkASSERT(mRenderThread.getGrContext() != nullptr);
+            surface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
+                    info);
+        }
+        vd->updateCache(surface);
+    }
+    mVectorDrawables.clear();
+}
+
 void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
         const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
         sk_sp<SkSurface> surface) {
 
+    renderVectorDrawableCache();
+
     // draw all layers up front
     renderLayersImpl(layers, opaque);
 
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index c58fedf..6f5e719 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -49,6 +49,8 @@
             const std::vector< sp<RenderNode> >& nodes, bool opaque, const Rect &contentDrawBounds,
             sk_sp<SkSurface> surface);
 
+    std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
+
     static void destroyLayer(RenderNode* node);
 
     static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap);
@@ -119,8 +121,18 @@
             const std::vector< sp<RenderNode> >& nodes, const Rect &contentDrawBounds,
             sk_sp<SkSurface>);
 
+    /**
+     *  Render mVectorDrawables into offscreen buffers.
+     */
+    void renderVectorDrawableCache();
+
     TaskManager mTaskManager;
     std::vector<sk_sp<SkImage>> mPinnedImages;
+
+    /**
+     *  populated by prepareTree with dirty VDs
+     */
+    std::vector<VectorDrawableRoot*> mVectorDrawables;
     static float mLightRadius;
     static uint8_t mAmbientShadowAlpha;
     static uint8_t mSpotShadowAlpha;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 559d268..27edc25 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -126,22 +126,7 @@
          return SkRect::MakeLargest();
      }
      virtual void onDraw(SkCanvas* canvas) override {
-         Bitmap& hwuiBitmap = mRoot->getBitmapUpdateIfDirty();
-         SkBitmap bitmap;
-         hwuiBitmap.getSkBitmap(&bitmap);
-         SkPaint* paint = mRoot->getPaint();
-         canvas->drawBitmapRect(bitmap, mRoot->mutateProperties()->getBounds(), paint);
-         /*
-          * TODO we can draw this directly but need to address the following...
-          *
-          * 1) Add drawDirect(SkCanvas*) to VectorDrawableRoot
-          * 2) fix VectorDrawable.cpp's Path::draw to not make a temporary path
-          *    so that we don't break caching
-          * 3) figure out how to set path's as volatile during animation
-          * 4) if mRoot->getPaint() != null either promote to layer (during
-          *    animation) or cache in SkSurface (for static content)
-          *
-          */
+         mRoot->draw(canvas);
      }
 
  private:
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 738c091..33eda96 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -194,6 +194,8 @@
 
     void waitOnFences();
 
+    IRenderPipeline* getRenderPipeline() { return mRenderPipeline.get(); }
+
 private:
     CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
             IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index 7ae58a6..e15f5d9 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -17,6 +17,7 @@
 #include "tests/common/TestUtils.h"
 
 #include <gtest/gtest.h>
+#include <SkBlurDrawLooper.h>
 #include <SkColorMatrixFilter.h>
 #include <SkColorSpace.h>
 #include <SkImagePriv.h>
@@ -95,3 +96,16 @@
     sk_sp<SkColorSpace> sRGB2 = SkColorSpace::MakeSRGB();
     ASSERT_EQ(sRGB1.get(), sRGB2.get());
 }
+
+TEST(SkiaBehavior, blurDrawLooper) {
+    sk_sp<SkDrawLooper> looper = SkBlurDrawLooper::Make(SK_ColorRED, 5.0f, 3.0f, 4.0f);
+
+    SkDrawLooper::BlurShadowRec blur;
+    bool success = looper->asABlurShadow(&blur);
+    ASSERT_TRUE(success);
+
+    ASSERT_EQ(SK_ColorRED, blur.fColor);
+    ASSERT_EQ(5.0f, blur.fSigma);
+    ASSERT_EQ(3.0f, blur.fOffset.fX);
+    ASSERT_EQ(4.0f, blur.fOffset.fY);
+}
diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java
index abf6b20..2a0e04e 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/media/java/android/media/ImageUtils.java
@@ -62,6 +62,7 @@
             case ImageFormat.RAW12:
             case ImageFormat.DEPTH16:
             case ImageFormat.DEPTH_POINT_CLOUD:
+            case ImageFormat.RAW_DEPTH:
                 return 1;
             case ImageFormat.PRIVATE:
                 return 0;
@@ -103,6 +104,10 @@
             throw new IllegalArgumentException(
                     "Copy of RAW_OPAQUE format has not been implemented");
         }
+        if (src.getFormat() == ImageFormat.RAW_DEPTH) {
+            throw new IllegalArgumentException(
+                    "Copy of RAW_DEPTH format has not been implemented");
+        }
         if (!(dst.getOwner() instanceof ImageWriter)) {
             throw new IllegalArgumentException("Destination image is not from ImageWriter. Only"
                     + " the images from ImageWriter are writable");
@@ -206,6 +211,7 @@
             case PixelFormat.RGB_565:
             case ImageFormat.YUY2:
             case ImageFormat.Y16:
+            case ImageFormat.RAW_DEPTH:
             case ImageFormat.RAW_SENSOR:
             case ImageFormat.RAW_PRIVATE: // round estimate, real size is unknown
             case ImageFormat.DEPTH16:
@@ -253,6 +259,7 @@
             case ImageFormat.RAW_SENSOR:
             case ImageFormat.RAW10:
             case ImageFormat.RAW12:
+            case ImageFormat.RAW_DEPTH:
                 return new Size(image.getWidth(), image.getHeight());
             case ImageFormat.PRIVATE:
                 return new Size(0, 0);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index 1b6aca1..227d804 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -110,6 +110,11 @@
     private final ScanCallback mBLEScanCallback = new ScanCallback() {
         @Override
         public void onScanResult(int callbackType, ScanResult result) {
+            if (DEBUG) {
+                Log.i(LOG_TAG,
+                        "BLE.onScanResult(callbackType = " + callbackType + ", result = " + result
+                                + ")");
+            }
             final DeviceFilterPair<ScanResult> deviceFilterPair
                     = DeviceFilterPair.findMatch(result, mBLEFilters);
             if (deviceFilterPair == null) return;
@@ -126,6 +131,10 @@
     private BroadcastReceiver mBluetoothDeviceFoundBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
+            if (DEBUG) {
+                Log.i(LOG_TAG,
+                        "BL.onReceive(context = " + context + ", intent = " + intent + ")");
+            }
             final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
             final DeviceFilterPair<BluetoothDevice> deviceFilterPair
                     = DeviceFilterPair.findMatch(device, mBluetoothFilters);
@@ -191,7 +200,10 @@
             mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLEDeviceFilter::getScanFilter);
 
             reset();
-        }
+        } else if (DEBUG) Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request);
+
+
+
         if (!ArrayUtils.isEmpty(mDevicesFound)) {
             onReadyToShowUI();
         }
@@ -221,6 +233,7 @@
     }
 
     private void reset() {
+        if (DEBUG) Log.i(LOG_TAG, "reset()");
         mDevicesFound.clear();
         mSelectedDevice = null;
         mDevicesAdapter.notifyDataSetChanged();
@@ -369,8 +382,15 @@
         public static <T extends Parcelable> DeviceFilterPair<T> findMatch(
                 T dev, @Nullable List<? extends DeviceFilter<T>> filters) {
             if (isEmpty(filters)) return new DeviceFilterPair<>(dev, null);
-            final DeviceFilter<T> matchingFilter = CollectionUtils.find(filters, (f) -> f.matches(dev));
-            return matchingFilter != null ? new DeviceFilterPair<>(dev, matchingFilter) : null;
+            final DeviceFilter<T> matchingFilter
+                    = CollectionUtils.find(filters, f -> f.matches(dev));
+
+            DeviceFilterPair<T> result = matchingFilter != null
+                    ? new DeviceFilterPair<>(dev, matchingFilter)
+                    : null;
+            if (DEBUG) Log.i(LOG_TAG, "findMatch(dev = " + dev + ", filters = " + filters +
+                    ") -> " + result);
+            return result;
         }
 
         public String getDisplayName() {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 187e35a..f11a9cd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -113,12 +113,14 @@
                             }
                             // Notify we are done.
                             mState = STATE_UPDATED;
+                            mDocumentInfo.updated = true;
                             notifyUpdateCompleted();
                         }
                     }
                 } else {
                     // We always notify after a write.
                     mState = STATE_UPDATED;
+                    mDocumentInfo.updated = true;
                     notifyUpdateCompleted();
                 }
                 runPendingCommand();
@@ -229,6 +231,7 @@
                   mDocumentInfo, oldAttributes, attributes, preview, mCommandResultCallback);
             scheduleCommand(command);
 
+            mDocumentInfo.updated = false;
             mState = STATE_UPDATING;
         // If no layout in progress and we don't have all pages - schedule a write.
         } else if ((!(mCurrentCommand instanceof LayoutCommand)
@@ -249,6 +252,7 @@
                     mDocumentInfo.fileProvider, mCommandResultCallback);
             scheduleCommand(command);
 
+            mDocumentInfo.updated = false;
             mState = STATE_UPDATING;
         } else {
             willUpdate = false;
@@ -396,7 +400,7 @@
 
     private void notifyUpdateFailed(CharSequence error) {
         if (DEBUG) {
-            Log.i(LOG_TAG, "[CALLING] onUpdateCompleted()");
+            Log.i(LOG_TAG, "[CALLING] notifyUpdateFailed()");
         }
         mUpdateCallbacks.onUpdateFailed(error);
     }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index f6df995..4cce166 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -491,8 +491,6 @@
 
         setState(STATE_UPDATE_FAILED);
 
-        updateOptionsUi();
-
         mPrintedDocument.kill(message);
     }
 
@@ -502,7 +500,6 @@
                 && canUpdateDocument() && updateDocument(true)) {
             ensurePreviewUiShown();
             setState(STATE_CONFIGURING);
-            updateOptionsUi();
         }
     }
 
@@ -579,7 +576,6 @@
                 updatePrintPreviewController(document.changed);
 
                 setState(STATE_CONFIGURING);
-                updateOptionsUi();
             } break;
         }
     }
@@ -600,8 +596,6 @@
         }
 
         setState(STATE_UPDATE_FAILED);
-
-        updateOptionsUi();
     }
 
     @Override
@@ -734,7 +728,6 @@
             updateOptionsUi();
         } else {
             setState(STATE_CREATE_FILE_FAILED);
-            updateOptionsUi();
             // Calling finish here does not invoke lifecycle callbacks but we
             // update the print job in onPause if finishing, hence post a message.
             mDestinationSpinner.post(new Runnable() {
@@ -958,12 +951,14 @@
                     Log.i(LOG_TAG, "[state]" + state);
                 }
                 mState = state;
+                updateOptionsUi();
             }
         } else {
             if (DEBUG) {
                 Log.i(LOG_TAG, "[state]" + state);
             }
             mState = state;
+            updateOptionsUi();
         }
     }
 
@@ -1230,6 +1225,7 @@
 
         final boolean willUpdate = mPrintedDocument.update(mPrintJob.getAttributes(),
                 pages, preview);
+        updateOptionsUi();
 
         if (willUpdate && !mPrintedDocument.hasLaidOutPages()) {
             // When the update is done we update the print preview.
@@ -1254,7 +1250,6 @@
 
     private void cancelPrint() {
         setState(STATE_PRINT_CANCELED);
-        updateOptionsUi();
         mPrintedDocument.cancel(true);
         doFinish();
     }
@@ -1274,7 +1269,6 @@
     private void confirmPrint() {
         setState(STATE_PRINT_CONFIRMED);
 
-        updateOptionsUi();
         addCurrentPrinterToHistory();
         setUserPrinted();
 
@@ -1629,6 +1623,8 @@
         // Always update the summary.
         updateSummary();
 
+        mDestinationSpinner.setEnabled(!isFinalState(mState));
+
         if (mState == STATE_PRINT_CONFIRMED
                 || mState == STATE_PRINT_COMPLETED
                 || mState == STATE_PRINT_CANCELED
@@ -1636,9 +1632,6 @@
                 || mState == STATE_CREATE_FILE_FAILED
                 || mState == STATE_PRINTER_UNAVAILABLE
                 || mState == STATE_UPDATE_SLOW) {
-            if (mState != STATE_PRINTER_UNAVAILABLE) {
-                mDestinationSpinner.setEnabled(false);
-            }
             disableOptionsUi(isFinalState(mState));
             return;
         }
@@ -1927,7 +1920,7 @@
             mPrintButton.setImageResource(R.drawable.ic_menu_savetopdf);
             mPrintButton.setContentDescription(getString(R.string.savetopdf_button));
         }
-        if (!mPrintedDocument.getDocumentInfo().laidout
+        if (!mPrintedDocument.getDocumentInfo().updated
                 ||(mRangeOptionsSpinner.getSelectedItemPosition() == 1
                 && (TextUtils.isEmpty(mPageRangeEditText.getText()) || hasErrors()))
                 || (mRangeOptionsSpinner.getSelectedItemPosition() == 0
@@ -2048,7 +2041,6 @@
                 updateDocument(false);
             }
             ensurePreviewUiShown();
-            updateOptionsUi();
         }
     }
 
@@ -2058,7 +2050,6 @@
             mPrintedDocument.cancel(false);
             ensureErrorUiShown(getString(R.string.print_error_printer_unavailable),
                     PrintErrorFragment.ACTION_NONE);
-            updateOptionsUi();
         }
     }
 
@@ -3038,7 +3029,6 @@
             if (mState == STATE_UPDATE_SLOW) {
                 setState(STATE_UPDATE_SLOW);
                 ensureProgressUiShown();
-                updateOptionsUi();
 
                 return;
             } else if (mPosted) {
@@ -3080,7 +3070,6 @@
             mPreviousState = mState;
             setState(STATE_UPDATE_SLOW);
             ensureProgressUiShown();
-            updateOptionsUi();
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
index 4b0ab59..b54d7e20 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
@@ -106,11 +106,11 @@
 
     public SuggestionParser(
         Context context, SharedPreferences sharedPrefs, int orderXml, String smartDismissControl) {
-        mContext = context;
-        mSuggestionList = (List<SuggestionCategory>) new SuggestionOrderInflater(mContext)
-                .parse(orderXml);
-        mSharedPrefs = sharedPrefs;
-        mSmartDismissControl = smartDismissControl;
+        this(
+                context,
+                sharedPrefs,
+                (List<SuggestionCategory>) new SuggestionOrderInflater(context).parse(orderXml),
+                smartDismissControl);
     }
 
     public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) {
@@ -118,12 +118,15 @@
     }
 
     @VisibleForTesting
-    public SuggestionParser(Context context, SharedPreferences sharedPrefs) {
+    public SuggestionParser(
+            Context context,
+            SharedPreferences sharedPrefs,
+            List<SuggestionCategory> suggestionList,
+            String smartDismissControl) {
         mContext = context;
-        mSuggestionList = new ArrayList<SuggestionCategory>();
+        mSuggestionList = suggestionList;
         mSharedPrefs = sharedPrefs;
-        mSmartDismissControl = DEFAULT_SMART_DISMISS_CONTROL;
-        Log.wtf(TAG, "Only use this constructor for testing");
+        mSmartDismissControl = smartDismissControl;
     }
 
     public List<Tile> getSuggestions() {
@@ -134,7 +137,19 @@
         List<Tile> suggestions = new ArrayList<>();
         final int N = mSuggestionList.size();
         for (int i = 0; i < N; i++) {
-            readSuggestions(mSuggestionList.get(i), suggestions, isSmartSuggestionEnabled);
+            final SuggestionCategory category = mSuggestionList.get(i);
+            if (category.exclusive) {
+                // If suggestions from an exclusive category are present, parsing is stopped
+                // and only suggestions from that category are displayed. Note that subsequent
+                // exclusive categories are also ignored.
+                List<Tile> exclusiveSuggestions = new ArrayList<>();
+                readSuggestions(category, exclusiveSuggestions, isSmartSuggestionEnabled);
+                if (!exclusiveSuggestions.isEmpty()) {
+                    return exclusiveSuggestions;
+                }
+            } else {
+                readSuggestions(category, suggestions, isSmartSuggestionEnabled);
+            }
         }
         return suggestions;
     }
@@ -368,6 +383,7 @@
         public String category;
         public String pkg;
         public boolean multiple;
+        public boolean exclusive;
     }
 
     private static class SuggestionOrderInflater {
@@ -377,6 +393,7 @@
         private static final String ATTR_CATEGORY = "category";
         private static final String ATTR_PACKAGE = "package";
         private static final String ATTR_MULTIPLE = "multiple";
+        private static final String ATTR_EXCLUSIVE = "exclusive";
 
         private final Context mContext;
 
@@ -451,6 +468,9 @@
                 category.pkg = attrs.getAttributeValue(null, ATTR_PACKAGE);
                 String multiple = attrs.getAttributeValue(null, ATTR_MULTIPLE);
                 category.multiple = !TextUtils.isEmpty(multiple) && Boolean.parseBoolean(multiple);
+                String exclusive = attrs.getAttributeValue(null, ATTR_EXCLUSIVE);
+                category.exclusive =
+                        !TextUtils.isEmpty(exclusive) && Boolean.parseBoolean(exclusive);
                 return category;
             } else {
                 throw new IllegalArgumentException("Unknown item " + name);
diff --git a/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml b/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
index 1eeafba..0e2ce3b 100644
--- a/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
+++ b/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
@@ -15,6 +15,8 @@
 -->
 
 <optional-steps>
+    <step category="com.android.settings.suggested.category.DEFERRED_SETUP"
+        exclusive="true" />
     <step category="com.android.settings.suggested.category.LOCK_SCREEN" />
     <step category="com.android.settings.suggested.category.EMAIL" />
     <step category="com.android.settings.suggested.category.PARTNER_ACCOUNT"
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java
index 7729dec..d534180 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java
@@ -16,11 +16,12 @@
 
 package com.android.settingslib;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
@@ -31,59 +32,59 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.res.ResourceLoader;
+import org.robolectric.res.builder.DefaultPackageManager;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
 @RunWith(SettingLibRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class SuggestionParserTest {
 
-    @Mock
-    private PackageManager mPackageManager;
     private Context mContext;
     private SuggestionParser mSuggestionParser;
-    private SuggestionParser.SuggestionCategory mSuggestioCategory;
+    private SuggestionParser.SuggestionCategory mMultipleCategory;
+    private SuggestionParser.SuggestionCategory mExclusiveCategory;
     private List<Tile> mSuggestionsBeforeDismiss;
     private List<Tile> mSuggestionsAfterDismiss;
     private SharedPreferences mPrefs;
     private Tile mSuggestion;
-    private List<ResolveInfo> mInfo;
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = spy(RuntimeEnvironment.application);
-        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        RuntimeEnvironment.setRobolectricPackageManager(
+                new TestPackageManager(RuntimeEnvironment.getAppResourceLoader()));
+        mContext = RuntimeEnvironment.application;
         mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
         mSuggestion = new Tile();
         mSuggestion.intent = new Intent("action");
         mSuggestion.intent.setComponent(new ComponentName("pkg", "cls"));
         mSuggestion.metaData = new Bundle();
+        mMultipleCategory = new SuggestionParser.SuggestionCategory();
+        mMultipleCategory.category = "category1";
+        mMultipleCategory.multiple = true;
+        mExclusiveCategory = new SuggestionParser.SuggestionCategory();
+        mExclusiveCategory.category = "category2";
+        mExclusiveCategory.exclusive = true;
         mSuggestionParser = new SuggestionParser(
-            mContext, mPrefs, R.xml.suggestion_ordering, "0,0");
-        mSuggestioCategory = new SuggestionParser.SuggestionCategory();
-        mSuggestioCategory.category = "category1";
-        mSuggestioCategory.multiple = true;
-        mInfo = new ArrayList<>();
+                mContext, mPrefs, Arrays.asList(mMultipleCategory, mExclusiveCategory), "0,0");
+
         ResolveInfo info1 = TileUtilsTest.newInfo(true, "category1");
         info1.activityInfo.packageName = "pkg";
         ResolveInfo info2 = TileUtilsTest.newInfo(true, "category1");
         info2.activityInfo.packageName = "pkg2";
-        mInfo.add(info1);
-        mInfo.add(info2);
-        when(mPackageManager.queryIntentActivitiesAsUser(
-            any(Intent.class), anyInt(), anyInt())).thenReturn(mInfo);
+        ResolveInfo info3 = TileUtilsTest.newInfo(true, "category2");
+        info3.activityInfo.packageName = "pkg3";
+
+        Intent intent1 = new Intent(Intent.ACTION_MAIN).addCategory("category1");
+        Intent intent2 = new Intent(Intent.ACTION_MAIN).addCategory("category2");
+        RuntimeEnvironment.getRobolectricPackageManager().addResolveInfoForIntent(intent1, info1);
+        RuntimeEnvironment.getRobolectricPackageManager().addResolveInfoForIntent(intent1, info2);
+        RuntimeEnvironment.getRobolectricPackageManager().addResolveInfoForIntent(intent2, info3);
     }
 
     @Test
@@ -99,30 +100,64 @@
     @Test
     public void testGetSuggestions_withoutSmartSuggestions() {
         readAndDismissSuggestion(false);
-        mSuggestionParser.readSuggestions(mSuggestioCategory, mSuggestionsAfterDismiss, false);
-        assertThat(mSuggestionsBeforeDismiss.size()).isEqualTo(2);
-        assertThat(mSuggestionsAfterDismiss.size()).isEqualTo(1);
+        mSuggestionParser.readSuggestions(mMultipleCategory, mSuggestionsAfterDismiss, false);
+        assertThat(mSuggestionsBeforeDismiss).hasSize(2);
+        assertThat(mSuggestionsAfterDismiss).hasSize(1);
         assertThat(mSuggestionsBeforeDismiss.get(1)).isEqualTo(mSuggestionsAfterDismiss.get(0));
     }
 
     @Test
     public void testGetSuggestions_withSmartSuggestions() {
         readAndDismissSuggestion(true);
-        assertThat(mSuggestionsBeforeDismiss.size()).isEqualTo(2);
-        assertThat(mSuggestionsAfterDismiss.size()).isEqualTo(2);
+        assertThat(mSuggestionsBeforeDismiss).hasSize(2);
+        assertThat(mSuggestionsAfterDismiss).hasSize(2);
         assertThat(mSuggestionsBeforeDismiss).isEqualTo(mSuggestionsAfterDismiss);
     }
 
+    @Test
+    public void testGetSuggestion_exclusiveNotAvailable() {
+        RuntimeEnvironment.getRobolectricPackageManager().removeResolveInfosForIntent(
+                new Intent(Intent.ACTION_MAIN).addCategory("category2"),
+                "pkg3");
+
+        // If exclusive item is not available, the other categories should be shown
+        final List<Tile> suggestions = mSuggestionParser.getSuggestions();
+        assertThat(suggestions).hasSize(2);
+        assertThat(suggestions.get(0).category).isEqualTo("category1");
+        assertThat(suggestions.get(1).category).isEqualTo("category1");
+    }
+
+    @Test
+    public void testGetSuggestions_exclusive() {
+        final List<Tile> suggestions = mSuggestionParser.getSuggestions();
+        assertThat(suggestions).hasSize(1);
+        assertThat(suggestions.get(0).category).isEqualTo("category2");
+    }
+
     private void readAndDismissSuggestion(boolean isSmartSuggestionEnabled) {
-        mSuggestionsBeforeDismiss = new ArrayList<Tile>();
-        mSuggestionsAfterDismiss = new ArrayList<Tile>();
+        mSuggestionsBeforeDismiss = new ArrayList<>();
+        mSuggestionsAfterDismiss = new ArrayList<>();
         mSuggestionParser.readSuggestions(
-            mSuggestioCategory, mSuggestionsBeforeDismiss, isSmartSuggestionEnabled);
-        if (mSuggestionParser.dismissSuggestion(
-            mSuggestionsBeforeDismiss.get(0), isSmartSuggestionEnabled)) {
-            mInfo.remove(0);
+                mMultipleCategory, mSuggestionsBeforeDismiss, isSmartSuggestionEnabled);
+        final Tile suggestion = mSuggestionsBeforeDismiss.get(0);
+        if (mSuggestionParser.dismissSuggestion(suggestion, isSmartSuggestionEnabled)) {
+            RuntimeEnvironment.getRobolectricPackageManager().removeResolveInfosForIntent(
+                    new Intent(Intent.ACTION_MAIN).addCategory(suggestion.category),
+                    suggestion.intent.getComponent().getPackageName());
         }
         mSuggestionParser.readSuggestions(
-            mSuggestioCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled);
+                mMultipleCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled);
+    }
+
+    private static class TestPackageManager extends DefaultPackageManager {
+
+        TestPackageManager(ResourceLoader appResourceLoader) {
+            super(appResourceLoader);
+        }
+
+        @Override
+        public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId) {
+            return super.queryIntentActivities(intent, flags);
+        }
     }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 2d3c4a7..dfbe43b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -16,11 +16,22 @@
 
 package com.android.settingslib.drawer;
 
-import android.app.ActivityManager;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
-import android.content.IContentProvider;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.IContentProvider;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -40,34 +51,23 @@
 
 import com.android.settingslib.SuggestionParser;
 import com.android.settingslib.TestConfig;
-import com.android.settingslib.drawer.TileUtilsTest;
-import static org.mockito.Mockito.atLeastOnce;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.robolectric.shadows.ShadowApplication;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-import org.mockito.ArgumentCaptor;
-
 
 @RunWith(RobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
@@ -179,7 +179,11 @@
                 false /* checkCategory */);
 
         assertThat(outTiles.size()).isEqualTo(1);
-        SuggestionParser parser = new SuggestionParser(mContext, null);
+        SuggestionParser parser = new SuggestionParser(
+                mContext,
+                null,
+                Collections.emptyList(),
+                "0,10");
         parser.filterSuggestions(outTiles, 0, false);
         assertThat(outTiles.size()).isEqualTo(0);
     }
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f15475c..6a75470 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -209,9 +209,12 @@
     <!-- Set to true to enable the user switcher on the keyguard. -->
     <bool name="config_keyguardUserSwitcher">false</bool>
 
-    <!-- Doze: does this device support STATE_DOZE and STATE_DOZE_SUSPEND?  -->
+    <!-- Doze: does this device support STATE_DOZE?  -->
     <bool name="doze_display_state_supported">false</bool>
 
+    <!-- Doze: does this device support STATE_DOZE_SUSPEND?  -->
+    <bool name="doze_suspend_display_state_supported">false</bool>
+
     <!-- Doze: should the significant motion sensor be used as a pulse signal? -->
     <bool name="doze_pulse_on_significant_motion">false</bool>
 
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 9a4179f..6571294 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -405,17 +405,17 @@
                     }
                 } else {
                     drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
+                    if (FIXED_SIZED_SURFACE) {
+                        // If the surface is fixed-size, we should only need to
+                        // draw it once and then we'll let the window manager
+                        // position it appropriately.  As such, we no longer needed
+                        // the loaded bitmap.  Yay!
+                        // hw-accelerated renderer retains bitmap for faster rotation
+                        unloadWallpaper(false /* forgetSize */);
+                    }
                 }
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-                if (FIXED_SIZED_SURFACE && !mIsHwAccelerated) {
-                    // If the surface is fixed-size, we should only need to
-                    // draw it once and then we'll let the window manager
-                    // position it appropriately.  As such, we no longer needed
-                    // the loaded bitmap.  Yay!
-                    // hw-accelerated renderer retains bitmap for faster rotation
-                    unloadWallpaper(false /* forgetSize */);
-                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index ba8e54a..4d8323b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -50,7 +50,8 @@
         WakeLock wakeLock = WakeLock.createPartial(context, "Doze");
 
         DozeMachine machine = new DozeMachine(
-                DozeScreenStatePreventingAdapter.wrapIfNeeded(dozeService, params),
+                DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(
+                        DozeScreenStatePreventingAdapter.wrapIfNeeded(dozeService, params), params),
                 config,
                 wakeLock);
         machine.setParts(new DozeMachine.Part[]{
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index f27521e..f498410 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -87,8 +87,9 @@
                 case DOZE:
                     return Display.STATE_OFF;
                 case DOZE_PULSING:
+                    return Display.STATE_DOZE;
                 case DOZE_AOD:
-                    return Display.STATE_DOZE; // TODO: use STATE_ON if appropriate.
+                    return Display.STATE_DOZE_SUSPEND;
                 default:
                     return Display.STATE_UNKNOWN;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapter.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapter.java
new file mode 100644
index 0000000..1e06797
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.doze;
+
+import android.support.annotation.VisibleForTesting;
+import android.view.Display;
+
+import com.android.systemui.statusbar.phone.DozeParameters;
+
+/**
+ * Prevents usage of doze screen states on devices that don't support them.
+ */
+public class DozeSuspendScreenStatePreventingAdapter implements DozeMachine.Service {
+
+    private final DozeMachine.Service mInner;
+
+    @VisibleForTesting
+    DozeSuspendScreenStatePreventingAdapter(DozeMachine.Service inner) {
+        mInner = inner;
+    }
+
+    @Override
+    public void finish() {
+        mInner.finish();
+    }
+
+    @Override
+    public void setDozeScreenState(int state) {
+        if (state == Display.STATE_DOZE_SUSPEND) {
+            state = Display.STATE_DOZE;
+        }
+        mInner.setDozeScreenState(state);
+    }
+
+    @Override
+    public void requestWakeUp() {
+        mInner.requestWakeUp();
+    }
+
+    /**
+     * If the device supports the doze display state, return {@code inner}. Otherwise
+     * return a new instance of {@link DozeSuspendScreenStatePreventingAdapter} wrapping {@code inner}.
+     */
+    public static DozeMachine.Service wrapIfNeeded(DozeMachine.Service inner,
+            DozeParameters params) {
+        return isNeeded(params) ? new DozeSuspendScreenStatePreventingAdapter(inner) : inner;
+    }
+
+    private static boolean isNeeded(DozeParameters params) {
+        return !params.getDozeSuspendDisplayStateSupported();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index ebda2e8..ec80745 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -45,14 +45,12 @@
 import android.os.Messenger;
 import android.os.RemoteException;
 import android.util.Log;
-import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.WindowManager.LayoutParams;
-import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -61,6 +59,7 @@
 import com.android.systemui.R;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -128,8 +127,9 @@
                     break;
                 case MESSAGE_UPDATE_ACTIONS: {
                     final Bundle data = (Bundle) msg.obj;
-                    setActions(data.getParcelable(EXTRA_STACK_BOUNDS),
-                            ((ParceledListSlice) data.getParcelable(EXTRA_ACTIONS)).getList());
+                    final ParceledListSlice actions = data.getParcelable(EXTRA_ACTIONS);
+                    setActions(data.getParcelable(EXTRA_STACK_BOUNDS), actions != null
+                            ? actions.getList() : Collections.EMPTY_LIST);
                     break;
                 }
                 case MESSAGE_UPDATE_DISMISS_FRACTION: {
@@ -260,6 +260,7 @@
             }
             notifyMenuVisibility(true);
             updateExpandButtonFromBounds(stackBounds, movementBounds);
+            setDecorViewVisibility(true);
             mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
                     mMenuContainer.getAlpha(), 1f);
             mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
@@ -300,9 +301,7 @@
                     if (animationFinishedRunnable != null) {
                         animationFinishedRunnable.run();
                     }
-                    if (getSystemService(AccessibilityManager.class).isEnabled()) {
-                        finish();
-                    }
+                    setDecorViewVisibility(false);
                 }
             });
             mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
@@ -411,6 +410,7 @@
     }
 
     private void updateDismissFraction(float fraction) {
+        setDecorViewVisibility(true);
         int alpha;
         if (mMenuVisible) {
             mMenuContainer.setAlpha(1-fraction);
@@ -497,4 +497,16 @@
         v.removeCallbacks(mFinishRunnable);
         v.postDelayed(mFinishRunnable, delay);
     }
+
+    /**
+     * Sets the visibility of the root view of the window to disable drawing and touches for the
+     * activity.  This differs from {@link Activity#setVisible(boolean)} in that it does not set
+     * the internal mVisibleFromClient state.
+     */
+    private void setDecorViewVisibility(boolean visible) {
+        final View decorView = getWindow().getDecorView();
+        if (decorView != null) {
+            decorView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 7b2e997..2a9de41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -80,6 +80,10 @@
         return getBoolean("doze.display.supported", R.bool.doze_display_state_supported);
     }
 
+    public boolean getDozeSuspendDisplayStateSupported() {
+        return mContext.getResources().getBoolean(R.bool.doze_suspend_display_state_supported);
+    }
+
     public int getPulseDuration(boolean pickup) {
         return getPulseInDuration(pickup) + getPulseVisibleDuration() + getPulseOutDuration();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index cdbde5e..5771b28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -228,7 +228,7 @@
 
         mMachine.requestState(DOZE_AOD);
 
-        assertEquals(Display.STATE_DOZE, mServiceFake.screenState);
+        assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
     }
 
     @Test
@@ -258,7 +258,7 @@
         mMachine.requestState(DOZE_AOD);
         mMachine.requestState(DOZE_REQUEST_PULSE);
 
-        assertEquals(Display.STATE_DOZE, mServiceFake.screenState);
+        assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
new file mode 100644
index 0000000..2e3df2c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.doze;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.view.Display;
+
+import com.android.systemui.statusbar.phone.DozeParameters;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@SmallTest
+public class DozeSuspendScreenStatePreventingAdapterTest {
+
+    private DozeMachine.Service mInner;
+    private DozeSuspendScreenStatePreventingAdapter mWrapper;
+
+    @Before
+    public void setup() throws Exception {
+        mInner = mock(DozeMachine.Service.class);
+        mWrapper = new DozeSuspendScreenStatePreventingAdapter(mInner);
+    }
+
+    @Test
+    public void forwards_finish() throws Exception {
+        mWrapper.finish();
+        verify(mInner).finish();
+    }
+
+    @Test
+    public void forwards_setDozeScreenState_on() throws Exception {
+        mWrapper.setDozeScreenState(Display.STATE_ON);
+        verify(mInner).setDozeScreenState(Display.STATE_ON);
+    }
+
+    @Test
+    public void forwards_setDozeScreenState_off() throws Exception {
+        mWrapper.setDozeScreenState(Display.STATE_OFF);
+        verify(mInner).setDozeScreenState(Display.STATE_OFF);
+    }
+
+    @Test
+    public void forwards_setDozeScreenState_doze() throws Exception {
+        mWrapper.setDozeScreenState(Display.STATE_DOZE);
+        verify(mInner).setDozeScreenState(Display.STATE_DOZE);
+    }
+
+    @Test
+    public void forwards_setDozeScreenState_doze_suspend() throws Exception {
+        mWrapper.setDozeScreenState(Display.STATE_DOZE_SUSPEND);
+        verify(mInner).setDozeScreenState(Display.STATE_DOZE);
+    }
+
+    @Test
+    public void forwards_requestWakeUp() throws Exception {
+        mWrapper.requestWakeUp();
+        verify(mInner).requestWakeUp();
+    }
+
+    @Test
+    public void wrapIfNeeded_needed() throws Exception {
+        DozeParameters params = mock(DozeParameters.class);
+        when(params.getDozeSuspendDisplayStateSupported()).thenReturn(false);
+
+        assertEquals(DozeSuspendScreenStatePreventingAdapter.class,
+                DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(mInner, params).getClass());
+    }
+
+    @Test
+    public void wrapIfNeeded_not_needed() throws Exception {
+        DozeParameters params = mock(DozeParameters.class);
+        when(params.getDozeSuspendDisplayStateSupported()).thenReturn(true);
+
+        assertSame(mInner, DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(mInner, params));
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/FontManagerService.java b/services/core/java/com/android/server/FontManagerService.java
index 55a945a..f172647 100644
--- a/services/core/java/com/android/server/FontManagerService.java
+++ b/services/core/java/com/android/server/FontManagerService.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.graphics.FontListParser;
+import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.text.FontConfig;
 import android.util.Slog;
@@ -34,6 +35,7 @@
 public class FontManagerService extends IFontManager.Stub {
     private static final String TAG = "FontManagerService";
     private static final String FONTS_CONFIG = "/system/etc/fonts.xml";
+    private static final String SYSTEM_FONT_DIR = "/system/fonts/";
 
     @GuardedBy("mLock")
     private FontConfig mConfig;
@@ -63,28 +65,22 @@
     public FontConfig getSystemFonts() {
         synchronized (mLock) {
             if (mConfig != null) {
-                return new FontConfig(mConfig);
+                return mConfig;
             }
 
-            FontConfig config = loadFromSystem();
-            if (config == null) {
+            mConfig = loadFromSystem();
+            if (mConfig == null) {
                 return null;
             }
 
-            for (FontConfig.Family family : config.getFamilies()) {
+            for (FontConfig.Family family : mConfig.getFamilies()) {
                 for (FontConfig.Font font : family.getFonts()) {
-                    File fontFile = new File(font.getFontName());
-                    try {
-                        font.setFd(ParcelFileDescriptor.open(
-                                fontFile, ParcelFileDescriptor.MODE_READ_ONLY));
-                    } catch (IOException e) {
-                        Slog.e(TAG, "Error opening font file " + font.getFontName(), e);
-                    }
+                    File fontFile = new File(SYSTEM_FONT_DIR, font.getFontName());
+                    font.setUri(Uri.fromFile(fontFile));
                 }
             }
 
-            mConfig = config;
-            return new FontConfig(mConfig);
+            return mConfig;
         }
     }
 
diff --git a/tools/layoutlib/.gitignore b/tools/layoutlib/.gitignore
index 819103d..a2b0c33 100644
--- a/tools/layoutlib/.gitignore
+++ b/tools/layoutlib/.gitignore
@@ -2,3 +2,4 @@
 /.idea/workspace.xml
 /out
 /bridge/out
+/.idea/kotlinc.xml
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
index e3bc34b..c20ee12 100644
--- a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
@@ -33,7 +33,6 @@
 import com.android.layoutlib.bridge.util.NinePatchInputStream;
 import com.android.ninepatch.NinePatch;
 import com.android.resources.ResourceType;
-import com.android.resources.ResourceUrl;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 import com.android.util.Pair;
 
@@ -60,8 +59,6 @@
 import java.io.InputStream;
 import java.util.Iterator;
 
-import static com.android.SdkConstants.ANDROID_NS_NAME;
-
 @SuppressWarnings("deprecation")
 public class Resources_Delegate {
 
@@ -140,8 +137,8 @@
 
             if (value == null) {
                 // Unable to resolve the attribute, just leave the unresolved value
-                value = new ResourceValue(ResourceUrl.create(resourceInfo.getFirst(), attributeName,
-                        platformResFlag_out[0]), attributeName);
+                value = new ResourceValue(resourceInfo.getFirst(), attributeName, attributeName,
+                        platformResFlag_out[0]);
             }
             return Pair.of(attributeName, value);
         }
@@ -681,7 +678,7 @@
         String packageName;
         if (resourceInfo != null) {
             if (platformOut[0]) {
-                packageName = ANDROID_NS_NAME;
+                packageName = SdkConstants.ANDROID_NS_NAME;
             } else {
                 packageName = resources.mContext.getPackageName();
                 packageName = packageName == null ? SdkConstants.APP_PREFIX : packageName;
@@ -699,7 +696,7 @@
         Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, platformOut);
         if (resourceInfo != null) {
             if (platformOut[0]) {
-                return ANDROID_NS_NAME;
+                return SdkConstants.ANDROID_NS_NAME;
             }
             String packageName = resources.mContext.getPackageName();
             return packageName == null ? SdkConstants.APP_PREFIX : packageName;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index e118889..80e3bad 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -233,7 +233,8 @@
             Map<String, ByteBuffer> bufferForPath) {
         FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
         for (FontConfig.Font font : family.getFonts()) {
-            FontFamily_Delegate.addFont(fontFamily.mBuilderPtr, font.getFontName(),
+            String fullPathName = "/system/fonts/" + font.getFontName();
+            FontFamily_Delegate.addFont(fontFamily.mBuilderPtr, fullPathName,
                     font.getWeight(), font.isItalic());
         }
         fontFamily.freeze();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 2e14974..93fd005 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -52,7 +52,6 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.util.Arrays;
-import java.util.Comparator;
 import java.util.EnumMap;
 import java.util.EnumSet;
 import java.util.HashMap;
@@ -62,7 +61,6 @@
 import libcore.io.MemoryMappedFile_Delegate;
 
 import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
-import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
 
 /**
  * Main entry point of the LayoutLib Bridge.
@@ -90,19 +88,14 @@
     /**
      * Maps from id to resource type/name. This is for com.android.internal.R
      */
-    private final static Map<Integer, Pair<ResourceType, String>> sRMap =
-        new HashMap<Integer, Pair<ResourceType, String>>();
+    @SuppressWarnings("deprecation")
+    private final static Map<Integer, Pair<ResourceType, String>> sRMap = new HashMap<>();
 
     /**
-     * Same as sRMap except for int[] instead of int resources. This is for android.R only.
-     */
-    private final static Map<IntArray, String> sRArrayMap = new HashMap<IntArray, String>(384);
-    /**
      * Reverse map compared to sRMap, resource type -> (resource name -> id).
      * This is for com.android.internal.R.
      */
-    private final static Map<ResourceType, Map<String, Integer>> sRevRMap =
-        new EnumMap<ResourceType, Map<String,Integer>>(ResourceType.class);
+    private final static Map<ResourceType, Map<String, Integer>> sRevRMap = new EnumMap<>(ResourceType.class);
 
     // framework resources are defined as 0x01XX#### where XX is the resource type (layout,
     // drawable, etc...). Using FF as the type allows for 255 resource types before we get a
@@ -111,56 +104,19 @@
     private final static DynamicIdMap sDynamicIds = new DynamicIdMap(DYNAMIC_ID_SEED_START);
 
     private final static Map<Object, Map<String, SoftReference<Bitmap>>> sProjectBitmapCache =
-        new HashMap<Object, Map<String, SoftReference<Bitmap>>>();
+            new HashMap<>();
     private final static Map<Object, Map<String, SoftReference<NinePatchChunk>>> sProject9PatchCache =
-        new HashMap<Object, Map<String, SoftReference<NinePatchChunk>>>();
 
-    private final static Map<String, SoftReference<Bitmap>> sFrameworkBitmapCache =
-        new HashMap<String, SoftReference<Bitmap>>();
+            new HashMap<>();
+
+    private final static Map<String, SoftReference<Bitmap>> sFrameworkBitmapCache = new HashMap<>();
     private final static Map<String, SoftReference<NinePatchChunk>> sFramework9PatchCache =
-        new HashMap<String, SoftReference<NinePatchChunk>>();
+            new HashMap<>();
 
     private static Map<String, Map<String, Integer>> sEnumValueMap;
     private static Map<String, String> sPlatformProperties;
 
     /**
-     * int[] wrapper to use as keys in maps.
-     */
-    private final static class IntArray {
-        private int[] mArray;
-
-        private IntArray() {
-            // do nothing
-        }
-
-        private IntArray(int[] a) {
-            mArray = a;
-        }
-
-        private void set(int[] a) {
-            mArray = a;
-        }
-
-        @Override
-        public int hashCode() {
-            return Arrays.hashCode(mArray);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) return true;
-            if (obj == null) return false;
-            if (getClass() != obj.getClass()) return false;
-
-            IntArray other = (IntArray) obj;
-            return Arrays.equals(mArray, other.mArray);
-        }
-    }
-
-    /** Instance of IntArrayWrapper to be reused in {@link #resolveResourceId(int[])}. */
-    private final static IntArray sIntArrayWrapper = new IntArray();
-
-    /**
      * A default log than prints to stdout/stderr.
      */
     private final static LayoutLog sDefaultLog = new LayoutLog() {
@@ -192,6 +148,7 @@
         return com.android.ide.common.rendering.api.Bridge.API_CURRENT;
     }
 
+    @SuppressWarnings("deprecation")
     @Override
     @Deprecated
     public EnumSet<Capability> getCapabilities() {
@@ -272,11 +229,11 @@
                         case STRING:
                         case STYLE:
                             // Slightly less than thousand entries in each.
-                            fullMap = new HashMap<String, Integer>(1280);
+                            fullMap = new HashMap<>(1280);
                             // no break.
                         default:
                             if (fullMap == null) {
-                                fullMap = new HashMap<String, Integer>();
+                                fullMap = new HashMap<>();
                             }
                             sRevRMap.put(resType, fullMap);
                     }
@@ -288,13 +245,9 @@
                             continue;
                         }
                         Class<?> type = f.getType();
-                        if (type.isArray()) {
-                            // if the object is an int[] we put it in sRArrayMap using an IntArray
-                            // wrapper that properly implements equals and hashcode for the array
-                            // objects, as required by the map contract.
-                            sRArrayMap.put(new IntArray((int[]) f.get(null)), f.getName());
-                        } else {
+                        if (!type.isArray()) {
                             Integer value = (Integer) f.get(null);
+                            //noinspection deprecation
                             sRMap.put(value, Pair.of(resType, f.getName()));
                             fullMap.put(f.getName(), value);
                         }
@@ -332,32 +285,29 @@
         // values, we try and find them from the styleables.
 
         // There were 1500 elements in this map at M timeframe.
-        Map<String, Integer> revRAttrMap = new HashMap<String, Integer>(2048);
+        Map<String, Integer> revRAttrMap = new HashMap<>(2048);
         sRevRMap.put(ResourceType.ATTR, revRAttrMap);
         // There were 2000 elements in this map at M timeframe.
-        Map<String, Integer> revRStyleableMap = new HashMap<String, Integer>(3072);
+        Map<String, Integer> revRStyleableMap = new HashMap<>(3072);
         sRevRMap.put(ResourceType.STYLEABLE, revRStyleableMap);
         Class<?> c = com.android.internal.R.styleable.class;
         Field[] fields = c.getDeclaredFields();
         // Sort the fields to bring all arrays to the beginning, so that indices into the array are
         // able to refer back to the arrays (i.e. no forward references).
-        Arrays.sort(fields, new Comparator<Field>() {
-            @Override
-            public int compare(Field o1, Field o2) {
-                if (o1 == o2) {
-                    return 0;
-                }
-                Class<?> t1 = o1.getType();
-                Class<?> t2 = o2.getType();
-                if (t1.isArray() && !t2.isArray()) {
-                    return -1;
-                } else if (t2.isArray() && !t1.isArray()) {
-                    return 1;
-                }
-                return o1.getName().compareTo(o2.getName());
+        Arrays.sort(fields, (o1, o2) -> {
+            if (o1 == o2) {
+                return 0;
             }
+            Class<?> t1 = o1.getType();
+            Class<?> t2 = o2.getType();
+            if (t1.isArray() && !t2.isArray()) {
+                return -1;
+            } else if (t2.isArray() && !t1.isArray()) {
+                return 1;
+            }
+            return o1.getName().compareTo(o2.getName());
         });
-        Map<String, int[]> styleables = new HashMap<String, int[]>();
+        Map<String, int[]> styleables = new HashMap<>();
         for (Field field : fields) {
             if (!isValidRField(field)) {
                 // Only consider public static fields that are int or int[].
@@ -367,7 +317,6 @@
             String name = field.getName();
             if (field.getType().isArray()) {
                 int[] styleableValue = (int[]) field.get(null);
-                sRArrayMap.put(new IntArray(styleableValue), name);
                 styleables.put(name, styleableValue);
                 continue;
             }
@@ -389,9 +338,11 @@
             if (arrayValue != null) {
                 String attrName = name.substring(arrayName.length() + 1);
                 int attrValue = arrayValue[index];
+                //noinspection deprecation
                 sRMap.put(attrValue, Pair.of(ResourceType.ATTR, attrName));
                 revRAttrMap.put(attrName, attrValue);
             }
+            //noinspection deprecation
             sRMap.put(index, Pair.of(ResourceType.STYLEABLE, name));
             revRStyleableMap.put(name, index);
         }
@@ -422,7 +373,7 @@
     @Override
     public RenderSession createSession(SessionParams params) {
         try {
-            Result lastResult = SUCCESS.createResult();
+            Result lastResult;
             RenderSessionImpl scene = new RenderSessionImpl(params);
             try {
                 prepareThread();
@@ -456,7 +407,7 @@
     @Override
     public Result renderDrawable(DrawableParams params) {
         try {
-            Result lastResult = SUCCESS.createResult();
+            Result lastResult;
             RenderDrawable action = new RenderDrawable(params);
             try {
                 prepareThread();
@@ -581,26 +532,16 @@
      * @return a Pair containing the resource type and name, or null if the id
      *     does not match any resource.
      */
+    @SuppressWarnings("deprecation")
     public static Pair<ResourceType, String> resolveResourceId(int value) {
         Pair<ResourceType, String> pair = sRMap.get(value);
         if (pair == null) {
             pair = sDynamicIds.resolveId(value);
-            if (pair == null) {
-                //System.out.println(String.format("Missing id: %1$08X (%1$d)", value));
-            }
         }
         return pair;
     }
 
     /**
-     * Returns the name of a framework resource whose value is an int array.
-     */
-    public static String resolveResourceId(int[] array) {
-        sIntArrayWrapper.set(array);
-        return sRArrayMap.get(sIntArrayWrapper);
-    }
-
-    /**
      * Returns the integer id of a framework resource, from a given resource type and resource name.
      * <p/>
      * If no resource is found, it creates a dynamic id for the resource.
@@ -674,16 +615,12 @@
      */
     public static void setCachedBitmap(String value, Bitmap bmp, Object projectKey) {
         if (projectKey != null) {
-            Map<String, SoftReference<Bitmap>> map = sProjectBitmapCache.get(projectKey);
+            Map<String, SoftReference<Bitmap>> map =
+                    sProjectBitmapCache.computeIfAbsent(projectKey, k -> new HashMap<>());
 
-            if (map == null) {
-                map = new HashMap<String, SoftReference<Bitmap>>();
-                sProjectBitmapCache.put(projectKey, map);
-            }
-
-            map.put(value, new SoftReference<Bitmap>(bmp));
+            map.put(value, new SoftReference<>(bmp));
         } else {
-            sFrameworkBitmapCache.put(value, new SoftReference<Bitmap>(bmp));
+            sFrameworkBitmapCache.put(value, new SoftReference<>(bmp));
         }
     }
 
@@ -722,16 +659,12 @@
      */
     public static void setCached9Patch(String value, NinePatchChunk ninePatch, Object projectKey) {
         if (projectKey != null) {
-            Map<String, SoftReference<NinePatchChunk>> map = sProject9PatchCache.get(projectKey);
+            Map<String, SoftReference<NinePatchChunk>> map =
+                    sProject9PatchCache.computeIfAbsent(projectKey, k -> new HashMap<>());
 
-            if (map == null) {
-                map = new HashMap<String, SoftReference<NinePatchChunk>>();
-                sProject9PatchCache.put(projectKey, map);
-            }
-
-            map.put(value, new SoftReference<NinePatchChunk>(ninePatch));
+            map.put(value, new SoftReference<>(ninePatch));
         } else {
-            sFramework9PatchCache.put(value, new SoftReference<NinePatchChunk>(ninePatch));
+            sFramework9PatchCache.put(value, new SoftReference<>(ninePatch));
         }
     }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 4f88232..4573f7a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -31,7 +31,6 @@
 import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.Stack;
 import com.android.resources.ResourceType;
-import com.android.resources.ResourceUrl;
 import com.android.util.Pair;
 import com.android.util.PropertiesMap;
 import com.android.util.PropertiesMap.Property;
@@ -87,6 +86,7 @@
 import android.view.BridgeInflater;
 import android.view.Display;
 import android.view.DisplayAdjustments;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
@@ -107,7 +107,6 @@
 import java.util.Map;
 
 import static android.os._Original_Build.VERSION_CODES.JELLY_BEAN_MR1;
-import static com.android.SdkConstants.ANDROID_NS_NAME;
 import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE;
 
 /**
@@ -122,23 +121,20 @@
 
     static {
         FRAMEWORK_PATCHED_VALUES.put("animateFirstView", new ResourceValue(
-                ResourceUrl.create(ANDROID_NS_NAME, ResourceType.BOOL, "animateFirstView"),
-                "false"));
-        FRAMEWORK_PATCHED_VALUES.put("animateLayoutChanges", new ResourceValue(
-                ResourceUrl.create(ANDROID_NS_NAME, ResourceType.BOOL, "animateLayoutChanges"),
-                "false"));
+                ResourceType.BOOL, "animateFirstView", "false", false));
+        FRAMEWORK_PATCHED_VALUES.put("animateLayoutChanges",
+                new ResourceValue(ResourceType.BOOL, "animateLayoutChanges", "false", false));
 
 
-        FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionItemLayout", new ResourceValue(
-                ResourceUrl.create(ANDROID_NS_NAME, ResourceType.LAYOUT,
-                        "textEditSuggestionItemLayout"), "text_edit_suggestion_item"));
-        FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionContainerLayout", new ResourceValue(
-                ResourceUrl.create(ANDROID_NS_NAME, ResourceType.LAYOUT,
-                        "textEditSuggestionContainerLayout"), "text_edit_suggestion_container"));
-        FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionHighlightStyle", new ResourceValue(
-                ResourceUrl.create(ANDROID_NS_NAME, ResourceType.STYLE,
-                        "textEditSuggestionHighlightStyle"),
-                "TextAppearance.Holo.SuggestionHighlight"));
+        FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionItemLayout",
+                new ResourceValue(ResourceType.LAYOUT, "textEditSuggestionItemLayout",
+                        "text_edit_suggestion_item", true));
+        FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionContainerLayout",
+                new ResourceValue(ResourceType.LAYOUT, "textEditSuggestionContainerLayout",
+                        "text_edit_suggestion_container", true));
+        FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionHighlightStyle",
+                new ResourceValue(ResourceType.STYLE, "textEditSuggestionHighlightStyle",
+                        "TextAppearance.Holo.SuggestionHighlight", true));
 
     }
 
@@ -971,9 +967,7 @@
                     // there is a value in the XML, but we need to resolve it in case it's
                     // referencing another resource or a theme value.
                     ta.bridgeSetValue(index, attrName, frameworkAttr,
-                            mRenderResources.resolveResValue(new ResourceValue(
-                                    ResourceUrl.create(ResourceType.STRING, attrName,
-                                            isPlatformFile), value)));
+                            mRenderResources.resolveValue(null, attrName, value, isPlatformFile));
                 }
             }
         }
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
index 00dddee..8739b7f 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
@@ -311,7 +311,6 @@
         sFrameworkRepo = null;
         sProjectResources = null;
         sLogger = null;
-        sBridge.dispose();
         sBridge = null;
 
         TestUtils.gc();
@@ -329,7 +328,6 @@
         RenderSession session = sBridge.createSession(params);
 
         try {
-
             if (frameTimeNanos != -1) {
                 session.setElapsedFrameTimeNanos(frameTimeNanos);
             }
@@ -338,11 +336,13 @@
                 getLogger().error(session.getResult().getException(),
                         session.getResult().getErrorMessage());
             }
-            // Render the session with a timeout of 50s.
-            Result renderResult = session.render(50000);
-            if (!renderResult.isSuccess()) {
-                getLogger().error(session.getResult().getException(),
-                        session.getResult().getErrorMessage());
+            else {
+                // Render the session with a timeout of 50s.
+                Result renderResult = session.render(50000);
+                if (!renderResult.isSuccess()) {
+                    getLogger().error(session.getResult().getException(),
+                            session.getResult().getErrorMessage());
+                }
             }
 
             return RenderResult.getFromSession(session);