Merge "Add api lint to upload checks"
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 42b0f6b..1503445 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -2,3 +2,8 @@
     name: "IKeyAttestationApplicationIdProvider.aidl",
     srcs: ["android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl"],
 }
+
+filegroup {
+    name: "IKeystoreService.aidl",
+    srcs: ["android/security/IKeystoreService.aidl"],
+}
diff --git a/core/java/android/hardware/usb/AccessoryFilter.java b/core/java/android/hardware/usb/AccessoryFilter.java
new file mode 100644
index 0000000..d9b7c5b
--- /dev/null
+++ b/core/java/android/hardware/usb/AccessoryFilter.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 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 android.hardware.usb;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * This class is used to describe a USB accessory.
+ * When used in HashMaps all values must be specified,
+ * but wildcards can be used for any of the fields in
+ * the package meta-data.
+ *
+ * @hide
+ */
+public class AccessoryFilter {
+    // USB accessory manufacturer (or null for unspecified)
+    public final String mManufacturer;
+    // USB accessory model (or null for unspecified)
+    public final String mModel;
+    // USB accessory version (or null for unspecified)
+    public final String mVersion;
+
+    public AccessoryFilter(String manufacturer, String model, String version) {
+        mManufacturer = manufacturer;
+        mModel = model;
+        mVersion = version;
+    }
+
+    public AccessoryFilter(UsbAccessory accessory) {
+        mManufacturer = accessory.getManufacturer();
+        mModel = accessory.getModel();
+        mVersion = accessory.getVersion();
+    }
+
+    public static AccessoryFilter read(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        String manufacturer = null;
+        String model = null;
+        String version = null;
+
+        int count = parser.getAttributeCount();
+        for (int i = 0; i < count; i++) {
+            String name = parser.getAttributeName(i);
+            String value = parser.getAttributeValue(i);
+
+            if ("manufacturer".equals(name)) {
+                manufacturer = value;
+            } else if ("model".equals(name)) {
+                model = value;
+            } else if ("version".equals(name)) {
+                version = value;
+            }
+        }
+        return new AccessoryFilter(manufacturer, model, version);
+    }
+
+    public void write(XmlSerializer serializer)throws IOException {
+        serializer.startTag(null, "usb-accessory");
+        if (mManufacturer != null) {
+            serializer.attribute(null, "manufacturer", mManufacturer);
+        }
+        if (mModel != null) {
+            serializer.attribute(null, "model", mModel);
+        }
+        if (mVersion != null) {
+            serializer.attribute(null, "version", mVersion);
+        }
+        serializer.endTag(null, "usb-accessory");
+    }
+
+    public boolean matches(UsbAccessory acc) {
+        if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
+        if (mModel != null && !acc.getModel().equals(mModel)) return false;
+        return !(mVersion != null && !acc.getVersion().equals(mVersion));
+    }
+
+    /**
+     * Is the accessories described {@code accessory} covered by this filter?
+     *
+     * @param accessory A filter describing the accessory
+     *
+     * @return {@code true} iff this the filter covers the accessory
+     */
+    public boolean contains(AccessoryFilter accessory) {
+        if (mManufacturer != null && !Objects.equals(accessory.mManufacturer, mManufacturer)) {
+            return false;
+        }
+        if (mModel != null && !Objects.equals(accessory.mModel, mModel)) return false;
+        return !(mVersion != null && !Objects.equals(accessory.mVersion, mVersion));
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        // can't compare if we have wildcard strings
+        if (mManufacturer == null || mModel == null || mVersion == null) {
+            return false;
+        }
+        if (obj instanceof AccessoryFilter) {
+            AccessoryFilter filter = (AccessoryFilter)obj;
+            return (mManufacturer.equals(filter.mManufacturer) &&
+                    mModel.equals(filter.mModel) &&
+                    mVersion.equals(filter.mVersion));
+        }
+        if (obj instanceof UsbAccessory) {
+            UsbAccessory accessory = (UsbAccessory)obj;
+            return (mManufacturer.equals(accessory.getManufacturer()) &&
+                    mModel.equals(accessory.getModel()) &&
+                    mVersion.equals(accessory.getVersion()));
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+                (mModel == null ? 0 : mModel.hashCode()) ^
+                (mVersion == null ? 0 : mVersion.hashCode()));
+    }
+
+    @Override
+    public String toString() {
+        return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
+                "\", mModel=\"" + mModel +
+                "\", mVersion=\"" + mVersion + "\"]";
+    }
+}
diff --git a/core/java/android/hardware/usb/DeviceFilter.java b/core/java/android/hardware/usb/DeviceFilter.java
new file mode 100644
index 0000000..439c629
--- /dev/null
+++ b/core/java/android/hardware/usb/DeviceFilter.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright 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 android.hardware.usb;
+
+import android.util.Slog;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * This class is used to describe a USB device.
+ * When used in HashMaps all values must be specified,
+ * but wildcards can be used for any of the fields in
+ * the package meta-data.
+ *
+ * @hide
+ */
+public class DeviceFilter {
+    private static final String TAG = DeviceFilter.class.getSimpleName();
+
+    // USB Vendor ID (or -1 for unspecified)
+    public final int mVendorId;
+    // USB Product ID (or -1 for unspecified)
+    public final int mProductId;
+    // USB device or interface class (or -1 for unspecified)
+    public final int mClass;
+    // USB device subclass (or -1 for unspecified)
+    public final int mSubclass;
+    // USB device protocol (or -1 for unspecified)
+    public final int mProtocol;
+    // USB device manufacturer name string (or null for unspecified)
+    public final String mManufacturerName;
+    // USB device product name string (or null for unspecified)
+    public final String mProductName;
+    // USB device serial number string (or null for unspecified)
+    public final String mSerialNumber;
+
+    public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol,
+            String manufacturer, String product, String serialnum) {
+        mVendorId = vid;
+        mProductId = pid;
+        mClass = clasz;
+        mSubclass = subclass;
+        mProtocol = protocol;
+        mManufacturerName = manufacturer;
+        mProductName = product;
+        mSerialNumber = serialnum;
+    }
+
+    public DeviceFilter(UsbDevice device) {
+        mVendorId = device.getVendorId();
+        mProductId = device.getProductId();
+        mClass = device.getDeviceClass();
+        mSubclass = device.getDeviceSubclass();
+        mProtocol = device.getDeviceProtocol();
+        mManufacturerName = device.getManufacturerName();
+        mProductName = device.getProductName();
+        mSerialNumber = device.getSerialNumber();
+    }
+
+    public static DeviceFilter read(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        int vendorId = -1;
+        int productId = -1;
+        int deviceClass = -1;
+        int deviceSubclass = -1;
+        int deviceProtocol = -1;
+        String manufacturerName = null;
+        String productName = null;
+        String serialNumber = null;
+
+        int count = parser.getAttributeCount();
+        for (int i = 0; i < count; i++) {
+            String name = parser.getAttributeName(i);
+            String value = parser.getAttributeValue(i);
+            // Attribute values are ints or strings
+            if ("manufacturer-name".equals(name)) {
+                manufacturerName = value;
+            } else if ("product-name".equals(name)) {
+                productName = value;
+            } else if ("serial-number".equals(name)) {
+                serialNumber = value;
+            } else {
+                int intValue;
+                int radix = 10;
+                if (value != null && value.length() > 2 && value.charAt(0) == '0' &&
+                        (value.charAt(1) == 'x' || value.charAt(1) == 'X')) {
+                    // allow hex values starting with 0x or 0X
+                    radix = 16;
+                    value = value.substring(2);
+                }
+                try {
+                    intValue = Integer.parseInt(value, radix);
+                } catch (NumberFormatException e) {
+                    Slog.e(TAG, "invalid number for field " + name, e);
+                    continue;
+                }
+                if ("vendor-id".equals(name)) {
+                    vendorId = intValue;
+                } else if ("product-id".equals(name)) {
+                    productId = intValue;
+                } else if ("class".equals(name)) {
+                    deviceClass = intValue;
+                } else if ("subclass".equals(name)) {
+                    deviceSubclass = intValue;
+                } else if ("protocol".equals(name)) {
+                    deviceProtocol = intValue;
+                }
+            }
+        }
+        return new DeviceFilter(vendorId, productId,
+                deviceClass, deviceSubclass, deviceProtocol,
+                manufacturerName, productName, serialNumber);
+    }
+
+    public void write(XmlSerializer serializer) throws IOException {
+        serializer.startTag(null, "usb-device");
+        if (mVendorId != -1) {
+            serializer.attribute(null, "vendor-id", Integer.toString(mVendorId));
+        }
+        if (mProductId != -1) {
+            serializer.attribute(null, "product-id", Integer.toString(mProductId));
+        }
+        if (mClass != -1) {
+            serializer.attribute(null, "class", Integer.toString(mClass));
+        }
+        if (mSubclass != -1) {
+            serializer.attribute(null, "subclass", Integer.toString(mSubclass));
+        }
+        if (mProtocol != -1) {
+            serializer.attribute(null, "protocol", Integer.toString(mProtocol));
+        }
+        if (mManufacturerName != null) {
+            serializer.attribute(null, "manufacturer-name", mManufacturerName);
+        }
+        if (mProductName != null) {
+            serializer.attribute(null, "product-name", mProductName);
+        }
+        if (mSerialNumber != null) {
+            serializer.attribute(null, "serial-number", mSerialNumber);
+        }
+        serializer.endTag(null, "usb-device");
+    }
+
+    private boolean matches(int clasz, int subclass, int protocol) {
+        return ((mClass == -1 || clasz == mClass) &&
+                (mSubclass == -1 || subclass == mSubclass) &&
+                (mProtocol == -1 || protocol == mProtocol));
+    }
+
+    public boolean matches(UsbDevice device) {
+        if (mVendorId != -1 && device.getVendorId() != mVendorId) return false;
+        if (mProductId != -1 && device.getProductId() != mProductId) return false;
+        if (mManufacturerName != null && device.getManufacturerName() == null) return false;
+        if (mProductName != null && device.getProductName() == null) return false;
+        if (mSerialNumber != null && device.getSerialNumber() == null) return false;
+        if (mManufacturerName != null && device.getManufacturerName() != null &&
+                !mManufacturerName.equals(device.getManufacturerName())) return false;
+        if (mProductName != null && device.getProductName() != null &&
+                !mProductName.equals(device.getProductName())) return false;
+        if (mSerialNumber != null && device.getSerialNumber() != null &&
+                !mSerialNumber.equals(device.getSerialNumber())) return false;
+
+        // check device class/subclass/protocol
+        if (matches(device.getDeviceClass(), device.getDeviceSubclass(),
+                device.getDeviceProtocol())) return true;
+
+        // if device doesn't match, check the interfaces
+        int count = device.getInterfaceCount();
+        for (int i = 0; i < count; i++) {
+            UsbInterface intf = device.getInterface(i);
+            if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
+                    intf.getInterfaceProtocol())) return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * If the device described by {@code device} covered by this filter?
+     *
+     * @param device The device
+     *
+     * @return {@code true} iff this filter covers the {@code device}
+     */
+    public boolean contains(DeviceFilter device) {
+        // -1 and null means "match anything"
+
+        if (mVendorId != -1 && device.mVendorId != mVendorId) return false;
+        if (mProductId != -1 && device.mProductId != mProductId) return false;
+        if (mManufacturerName != null && !Objects.equals(mManufacturerName,
+                device.mManufacturerName)) {
+            return false;
+        }
+        if (mProductName != null && !Objects.equals(mProductName, device.mProductName)) {
+            return false;
+        }
+        if (mSerialNumber != null
+                && !Objects.equals(mSerialNumber, device.mSerialNumber)) {
+            return false;
+        }
+
+        // check device class/subclass/protocol
+        return matches(device.mClass, device.mSubclass, device.mProtocol);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        // can't compare if we have wildcard strings
+        if (mVendorId == -1 || mProductId == -1 ||
+                mClass == -1 || mSubclass == -1 || mProtocol == -1) {
+            return false;
+        }
+        if (obj instanceof DeviceFilter) {
+            DeviceFilter filter = (DeviceFilter)obj;
+
+            if (filter.mVendorId != mVendorId ||
+                    filter.mProductId != mProductId ||
+                    filter.mClass != mClass ||
+                    filter.mSubclass != mSubclass ||
+                    filter.mProtocol != mProtocol) {
+                return(false);
+            }
+            if ((filter.mManufacturerName != null &&
+                    mManufacturerName == null) ||
+                    (filter.mManufacturerName == null &&
+                            mManufacturerName != null) ||
+                    (filter.mProductName != null &&
+                            mProductName == null)  ||
+                    (filter.mProductName == null &&
+                            mProductName != null) ||
+                    (filter.mSerialNumber != null &&
+                            mSerialNumber == null)  ||
+                    (filter.mSerialNumber == null &&
+                            mSerialNumber != null)) {
+                return(false);
+            }
+            if  ((filter.mManufacturerName != null &&
+                    mManufacturerName != null &&
+                    !mManufacturerName.equals(filter.mManufacturerName)) ||
+                    (filter.mProductName != null &&
+                            mProductName != null &&
+                            !mProductName.equals(filter.mProductName)) ||
+                    (filter.mSerialNumber != null &&
+                            mSerialNumber != null &&
+                            !mSerialNumber.equals(filter.mSerialNumber))) {
+                return false;
+            }
+            return true;
+        }
+        if (obj instanceof UsbDevice) {
+            UsbDevice device = (UsbDevice)obj;
+            if (device.getVendorId() != mVendorId ||
+                    device.getProductId() != mProductId ||
+                    device.getDeviceClass() != mClass ||
+                    device.getDeviceSubclass() != mSubclass ||
+                    device.getDeviceProtocol() != mProtocol) {
+                return(false);
+            }
+            if ((mManufacturerName != null && device.getManufacturerName() == null) ||
+                    (mManufacturerName == null && device.getManufacturerName() != null) ||
+                    (mProductName != null && device.getProductName() == null) ||
+                    (mProductName == null && device.getProductName() != null) ||
+                    (mSerialNumber != null && device.getSerialNumber() == null) ||
+                    (mSerialNumber == null && device.getSerialNumber() != null)) {
+                return(false);
+            }
+            if ((device.getManufacturerName() != null &&
+                    !mManufacturerName.equals(device.getManufacturerName())) ||
+                    (device.getProductName() != null &&
+                            !mProductName.equals(device.getProductName())) ||
+                    (device.getSerialNumber() != null &&
+                            !mSerialNumber.equals(device.getSerialNumber()))) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return (((mVendorId << 16) | mProductId) ^
+                ((mClass << 16) | (mSubclass << 8) | mProtocol));
+    }
+
+    @Override
+    public String toString() {
+        return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId +
+                ",mClass=" + mClass + ",mSubclass=" + mSubclass +
+                ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName +
+                ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber +
+                "]";
+    }
+}
diff --git a/core/java/android/security/KeystoreArguments.aidl b/core/java/android/security/KeystoreArguments.aidl
index d636414..dc8ed50 100644
--- a/core/java/android/security/KeystoreArguments.aidl
+++ b/core/java/android/security/KeystoreArguments.aidl
@@ -17,4 +17,4 @@
 package android.security;
 
 /* @hide */
-parcelable KeystoreArguments;
+parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h";
diff --git a/core/java/android/security/keymaster/ExportResult.aidl b/core/java/android/security/keymaster/ExportResult.aidl
index 4d9b2de..1748653 100644
--- a/core/java/android/security/keymaster/ExportResult.aidl
+++ b/core/java/android/security/keymaster/ExportResult.aidl
@@ -17,4 +17,4 @@
 package android.security.keymaster;
 
 /* @hide */
-parcelable ExportResult;
+parcelable ExportResult cpp_header "keystore/ExportResult.h";
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.aidl b/core/java/android/security/keymaster/KeyCharacteristics.aidl
index be739d3..32e75ad 100644
--- a/core/java/android/security/keymaster/KeyCharacteristics.aidl
+++ b/core/java/android/security/keymaster/KeyCharacteristics.aidl
@@ -17,4 +17,4 @@
 package android.security.keymaster;
 
 /* @hide */
-parcelable KeyCharacteristics;
+parcelable KeyCharacteristics cpp_header "keystore/KeyCharacteristics.h";
diff --git a/core/java/android/security/keymaster/KeymasterArguments.aidl b/core/java/android/security/keymaster/KeymasterArguments.aidl
index 1a73206..44d9f09 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.aidl
+++ b/core/java/android/security/keymaster/KeymasterArguments.aidl
@@ -17,4 +17,4 @@
 package android.security.keymaster;
 
 /* @hide */
-parcelable KeymasterArguments;
+parcelable KeymasterArguments cpp_header "keystore/KeymasterArguments.h";
diff --git a/core/java/android/security/keymaster/KeymasterBlob.aidl b/core/java/android/security/keymaster/KeymasterBlob.aidl
index b7cd1c9..5c5db9e 100644
--- a/core/java/android/security/keymaster/KeymasterBlob.aidl
+++ b/core/java/android/security/keymaster/KeymasterBlob.aidl
@@ -17,4 +17,4 @@
 package android.security.keymaster;
 
 /* @hide */
-parcelable KeymasterBlob;
+parcelable KeymasterBlob cpp_header "keystore/KeymasterBlob.h";
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
index dc1876a..ddb5cae 100644
--- a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
+++ b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
@@ -17,4 +17,4 @@
 package android.security.keymaster;
 
 /* @hide */
-parcelable KeymasterCertificateChain;
+parcelable KeymasterCertificateChain cpp_header "keystore/KeymasterCertificateChain.h";
diff --git a/core/java/android/security/keymaster/OperationResult.aidl b/core/java/android/security/keymaster/OperationResult.aidl
index ed26c8d..db689d4 100644
--- a/core/java/android/security/keymaster/OperationResult.aidl
+++ b/core/java/android/security/keymaster/OperationResult.aidl
@@ -17,4 +17,4 @@
 package android.security.keymaster;
 
 /* @hide */
-parcelable OperationResult;
+parcelable OperationResult cpp_header "keystore/OperationResult.h";
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 18afe6e..ac79249 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -137,15 +137,18 @@
 
 class StyleRun : public Run {
     public:
-        StyleRun(int32_t start, int32_t end, minikin::MinikinPaint&& paint, bool isRtl)
-            : Run(start, end), mPaint(std::move(paint)), mIsRtl(isRtl) {}
+        StyleRun(int32_t start, int32_t end, minikin::MinikinPaint&& paint,
+                std::shared_ptr<minikin::FontCollection>&& collection, bool isRtl)
+            : Run(start, end), mPaint(std::move(paint)), mCollection(std::move(collection)),
+              mIsRtl(isRtl) {}
 
         void addTo(minikin::LineBreaker* lineBreaker) override {
-            lineBreaker->addStyleRun(&mPaint, mStart, mEnd, mIsRtl);
+            lineBreaker->addStyleRun(&mPaint, mCollection, mStart, mEnd, mIsRtl);
         }
 
     private:
         minikin::MinikinPaint mPaint;
+        std::shared_ptr<minikin::FontCollection> mCollection;
         const bool mIsRtl;
 };
 
@@ -173,8 +176,10 @@
               mIndents(std::move(indents)), mLeftPaddings(std::move(leftPaddings)),
               mRightPaddings(std::move(rightPaddings)) {}
 
-        void addStyleRun(int32_t start, int32_t end, minikin::MinikinPaint&& paint, bool isRtl) {
-            mRuns.emplace_back(std::make_unique<StyleRun>(start, end, std::move(paint), isRtl));
+        void addStyleRun(int32_t start, int32_t end, minikin::MinikinPaint&& paint,
+                         std::shared_ptr<minikin::FontCollection> collection, bool isRtl) {
+            mRuns.emplace_back(std::make_unique<StyleRun>(
+                    start, end, std::move(paint), std::move(collection), isRtl));
         }
 
         void addReplacementRun(int32_t start, int32_t end, float width, uint32_t localeListId) {
@@ -329,7 +334,7 @@
     Paint* paint = reinterpret_cast<Paint*>(nativePaint);
     const Typeface* typeface = Typeface::resolveDefault(paint->getAndroidTypeface());
     minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(paint, typeface);
-    builder->addStyleRun(start, end, std::move(minikinPaint), isRtl);
+    builder->addStyleRun(start, end, std::move(minikinPaint), typeface->fFontCollection, isRtl);
 }
 
 // CriticalNative
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index a7469cd..399dddd 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -54,7 +54,7 @@
 public class KeyStore {
     private static final String TAG = "KeyStore";
 
-    // ResponseCodes
+    // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
     public static final int NO_ERROR = 1;
     public static final int LOCKED = 2;
     public static final int UNINITIALIZED = 3;
@@ -168,10 +168,14 @@
 
     public byte[] get(String key, int uid) {
         try {
+            key = key != null ? key : "";
             return mBinder.get(key, uid);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return null;
+        } catch (android.os.ServiceSpecificException e) {
+            Log.w(TAG, "KeyStore exception", e);
+            return null;
         }
     }
 
@@ -185,6 +189,9 @@
 
     public int insert(String key, byte[] value, int uid, int flags) {
         try {
+            if (value == null) {
+                value = new byte[0];
+            }
             return mBinder.insert(key, value, uid, flags);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
@@ -228,6 +235,9 @@
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return null;
+        } catch (android.os.ServiceSpecificException e) {
+            Log.w(TAG, "KeyStore exception", e);
+            return null;
         }
     }
 
@@ -276,6 +286,7 @@
      */
     public boolean unlock(int userId, String password) {
         try {
+            password = password != null ? password : "";
             mError = mBinder.unlock(userId, password);
             return mError == NO_ERROR;
         } catch (RemoteException e) {
@@ -330,16 +341,25 @@
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return null;
+        } catch (android.os.ServiceSpecificException e) {
+            Log.w(TAG, "KeyStore exception", e);
+            return null;
         }
+
     }
 
     public boolean verify(String key, byte[] data, byte[] signature) {
         try {
+            signature = signature != null ? signature : new byte[0];
             return mBinder.verify(key, data, signature) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
+        } catch (android.os.ServiceSpecificException e) {
+            Log.w(TAG, "KeyStore exception", e);
+            return false;
         }
+
     }
 
     public String grant(String key, int uid) {
@@ -432,6 +452,8 @@
     public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
             int flags, KeyCharacteristics outCharacteristics) {
         try {
+            entropy = entropy != null ? entropy : new byte[0];
+            args = args != null ? args : new KeymasterArguments();
             return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
@@ -447,6 +469,8 @@
     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
             int uid, KeyCharacteristics outCharacteristics) {
         try {
+            clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
+            appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
             return mBinder.getKeyCharacteristics(alias, clientId, appId, uid, outCharacteristics);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
@@ -478,6 +502,8 @@
     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
             KeymasterBlob appId, int uid) {
         try {
+            clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
+            appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
             return mBinder.exportKey(alias, format, clientId, appId, uid);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
@@ -492,6 +518,8 @@
     public OperationResult begin(String alias, int purpose, boolean pruneable,
             KeymasterArguments args, byte[] entropy, int uid) {
         try {
+            args = args != null ? args : new KeymasterArguments();
+            entropy = entropy != null ? entropy : new byte[0];
             return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
@@ -501,11 +529,15 @@
 
     public OperationResult begin(String alias, int purpose, boolean pruneable,
             KeymasterArguments args, byte[] entropy) {
+        entropy = entropy != null ? entropy : new byte[0];
+        args = args != null ? args : new KeymasterArguments();
         return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
     }
 
     public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
         try {
+            arguments = arguments != null ? arguments : new KeymasterArguments();
+            input = input != null ? input : new byte[0];
             return mBinder.update(token, arguments, input);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
@@ -516,6 +548,9 @@
     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
             byte[] entropy) {
         try {
+            arguments = arguments != null ? arguments : new KeymasterArguments();
+            entropy = entropy != null ? entropy : new byte[0];
+            signature = signature != null ? signature : new byte[0];
             return mBinder.finish(token, arguments, signature, entropy);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
@@ -632,6 +667,12 @@
     public int attestKey(
             String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
         try {
+            if (params == null) {
+                params = new KeymasterArguments();
+            }
+            if (outChain == null) {
+                outChain = new KeymasterCertificateChain();
+            }
             return mBinder.attestKey(alias, params, outChain);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
@@ -641,6 +682,12 @@
 
     public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
         try {
+            if (params == null) {
+                params = new KeymasterArguments();
+            }
+            if (outChain == null) {
+                outChain = new KeymasterCertificateChain();
+            }
             return mBinder.attestDeviceIds(params, outChain);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index 2a1a1f3..90fe0b7 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -30,43 +30,46 @@
                                                         const Typeface* typeface) {
     const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
     minikin::FontStyle resolved = resolvedFace->fStyle;
+
     const minikin::FontVariant minikinVariant =
             (paint->getFontVariant() == minikin::FontVariant::ELEGANT)
                     ? minikin::FontVariant::ELEGANT
                     : minikin::FontVariant::COMPACT;
-    float textSize = paint->getTextSize();
-    if (!paint->isLinearText()) {
-        // If linear text is not specified, truncate the value.
-        textSize = trunc(textSize);
-    }
-    return minikin::MinikinPaint(
-            textSize,
-            paint->getTextScaleX(),
-            paint->getTextSkewX(),
-            paint->getLetterSpacing(),
-            paint->getWordSpacing(),
-            MinikinFontSkia::packPaintFlags(paint),
-            paint->getMinikinLocaleListId(),
-            minikin::FontStyle(minikinVariant, resolved.weight, resolved.slant),
-            minikin::HyphenEdit(paint->getHyphenEdit()),
-            paint->getFontFeatureSettings(),
-            resolvedFace->fFontCollection);
+
+    minikin::MinikinPaint minikinPaint;
+    /* Prepare minikin Paint */
+    minikinPaint.size =
+            paint->isLinearText() ? paint->getTextSize() : static_cast<int>(paint->getTextSize());
+    minikinPaint.scaleX = paint->getTextScaleX();
+    minikinPaint.skewX = paint->getTextSkewX();
+    minikinPaint.letterSpacing = paint->getLetterSpacing();
+    minikinPaint.wordSpacing = paint->getWordSpacing();
+    minikinPaint.paintFlags = MinikinFontSkia::packPaintFlags(paint);
+    minikinPaint.localeListId = paint->getMinikinLocaleListId();
+    minikinPaint.fontStyle = minikin::FontStyle(minikinVariant, resolved.weight, resolved.slant);
+    minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings();
+    minikinPaint.hyphenEdit = minikin::HyphenEdit(paint->getHyphenEdit());
+    return minikinPaint;
 }
 
 minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFlags,
                                        const Typeface* typeface, const uint16_t* buf, size_t start,
                                        size_t count, size_t bufSize) {
+    minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
     minikin::Layout layout;
-    layout.doLayout(buf, start, count, bufSize, bidiFlags, prepareMinikinPaint(paint, typeface));
+    layout.doLayout(buf, start, count, bufSize, bidiFlags, minikinPaint,
+                    Typeface::resolveDefault(typeface)->fFontCollection);
     return layout;
 }
 
 float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags,
                                 const Typeface* typeface, const uint16_t* buf, size_t start,
                                 size_t count, size_t bufSize, float* advances) {
-    return minikin::Layout::measureText(
-            buf, start, count, bufSize, bidiFlags, prepareMinikinPaint(paint, typeface), advances,
-            nullptr /* extent */, nullptr /* overhangs */);
+    minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
+    const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
+    return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinPaint,
+                                        resolvedTypeface->fFontCollection, advances,
+                                        nullptr /* extent */, nullptr /* overhangs */);
 }
 
 bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 1536b64..b132160 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -124,16 +124,16 @@
     <string name="status_bar_use_physical_keyboard">Physical keyboard</string>
 
     <!-- Prompt for the USB device permission dialog [CHAR LIMIT=80] -->
-    <string name="usb_device_permission_prompt">Allow the app <xliff:g id="application">%1$s</xliff:g> to access the USB device?</string>
+    <string name="usb_device_permission_prompt">Allow <xliff:g id="application">%1$s</xliff:g> to access <xliff:g id="usb_device">%2$s</xliff:g>?</string>
 
     <!-- Prompt for the USB accessory permission dialog [CHAR LIMIT=80] -->
-    <string name="usb_accessory_permission_prompt">Allow the app <xliff:g id="application">%1$s</xliff:g> to access the USB accessory?</string>
+    <string name="usb_accessory_permission_prompt">Allow <xliff:g id="application">%1$s</xliff:g> to access <xliff:g id="usb_accessory">%2$s</xliff:g>?</string>
 
     <!-- Prompt for the USB device confirm dialog [CHAR LIMIT=80] -->
-    <string name="usb_device_confirm_prompt">Open <xliff:g id="activity">%1$s</xliff:g> when this USB device is connected?</string>
+    <string name="usb_device_confirm_prompt">Open <xliff:g id="application">%1$s</xliff:g> to handle <xliff:g id="usb_device">%2$s</xliff:g>?</string>
 
     <!-- Prompt for the USB accessory confirm dialog [CHAR LIMIT=80] -->
-    <string name="usb_accessory_confirm_prompt">Open <xliff:g id="activity">%1$s</xliff:g> when this USB accessory is connected?</string>
+    <string name="usb_accessory_confirm_prompt">Open <xliff:g id="application">%1$s</xliff:g> to handle <xliff:g id="usb_accessory">%2$s</xliff:g>?</string>
 
     <!-- Prompt for the USB accessory URI dialog [CHAR LIMIT=80] -->
     <string name="usb_accessory_uri_prompt">No installed apps work with this USB accessory. Learn more about this accessory at <xliff:g id="url">%1$s</xliff:g></string>
@@ -145,10 +145,10 @@
     <string name="label_view">View</string>
 
     <!-- Checkbox label for USB device dialogs.  [CHAR LIMIT=50] -->
-    <string name="always_use_device">Use by default for this USB device</string>
+    <string name="always_use_device">Always open <xliff:g id="application">%1$s</xliff:g> when <xliff:g id="usb_device">%2$s</xliff:g> is connected</string>
 
-    <!-- Checkbox label for USB accessory dialogs.  [CHAR LIMIT=50] -->
-    <string name="always_use_accessory">Use by default for this USB accessory</string>
+    <!-- Checkbox label for USB accessory dialogs.  [CHAR LIMIT=50]-->
+    <string name="always_use_accessory">Always open <xliff:g id="application">%1$s</xliff:g> when <xliff:g id="usb_accessory">%2$s</xliff:g> is connected</string>
 
     <!-- Title of confirmation dialog for USB debugging -->
     <string name="usb_debugging_title">Allow USB debugging?</string>
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
index 3eccccd..e117969 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -71,10 +71,12 @@
         ap.mIcon = mResolveInfo.loadIcon(packageManager);
         ap.mTitle = appName;
         if (mDevice == null) {
-            ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName);
+            ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName,
+                    mAccessory.getDescription());
             mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
         } else {
-            ap.mMessage = getString(R.string.usb_device_confirm_prompt, appName);
+            ap.mMessage = getString(R.string.usb_device_confirm_prompt, appName,
+                    mDevice.getProductName());
             mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
         }
         ap.mPositiveButtonText = getString(android.R.string.ok);
@@ -88,9 +90,11 @@
         ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
         mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
         if (mDevice == null) {
-            mAlwaysUse.setText(R.string.always_use_accessory);
+            mAlwaysUse.setText(getString(R.string.always_use_accessory, appName,
+                    mAccessory.getDescription()));
         } else {
-            mAlwaysUse.setText(R.string.always_use_device);
+            mAlwaysUse.setText(getString(R.string.always_use_device, appName,
+                    mDevice.getProductName()));
         }
         mAlwaysUse.setOnCheckedChangeListener(this);
         mClearDefaultHint = (TextView)ap.mView.findViewById(
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
index 1e69fc5..87d11b2 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -16,13 +16,17 @@
 
 package com.android.systemui.usb;
 
+import android.annotation.NonNull;
 import android.app.AlertDialog;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.res.XmlResourceParser;
 import android.hardware.usb.IUsbManager;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
@@ -41,8 +45,13 @@
 
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
+import com.android.internal.util.XmlUtils;
+import android.hardware.usb.AccessoryFilter;
+import android.hardware.usb.DeviceFilter;
 import com.android.systemui.R;
 
+import org.xmlpull.v1.XmlPullParser;
+
 public class UsbPermissionActivity extends AlertActivity
         implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
 
@@ -84,10 +93,12 @@
         ap.mIcon = aInfo.loadIcon(packageManager);
         ap.mTitle = appName;
         if (mDevice == null) {
-            ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName);
+            ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName,
+                    mAccessory.getDescription());
             mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
         } else {
-            ap.mMessage = getString(R.string.usb_device_permission_prompt, appName);
+            ap.mMessage = getString(R.string.usb_device_permission_prompt, appName,
+                    mDevice.getProductName());
             mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
         }
         ap.mPositiveButtonText = getString(android.R.string.ok);
@@ -95,25 +106,123 @@
         ap.mPositiveButtonListener = this;
         ap.mNegativeButtonListener = this;
 
-        // add "always use" checkbox
-        LayoutInflater inflater = (LayoutInflater)getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
-        mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
-        if (mDevice == null) {
-            mAlwaysUse.setText(R.string.always_use_accessory);
-        } else {
-            mAlwaysUse.setText(R.string.always_use_device);
+        try {
+            PackageInfo packageInfo = packageManager.getPackageInfo(mPackageName,
+                    PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
+
+            if ((mDevice != null && canBeDefault(mDevice, packageInfo))
+                    || (mAccessory != null && canBeDefault(mAccessory, packageInfo))) {
+                // add "open when" checkbox
+                LayoutInflater inflater = (LayoutInflater) getSystemService(
+                        Context.LAYOUT_INFLATER_SERVICE);
+                ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+                mAlwaysUse = (CheckBox) ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+                if (mDevice == null) {
+                    mAlwaysUse.setText(getString(R.string.always_use_accessory, appName,
+                            mAccessory.getDescription()));
+                } else {
+                    mAlwaysUse.setText(getString(R.string.always_use_device, appName,
+                            mDevice.getProductName()));
+                }
+                mAlwaysUse.setOnCheckedChangeListener(this);
+
+                mClearDefaultHint = (TextView)ap.mView.findViewById(
+                        com.android.internal.R.id.clearDefaultHint);
+                mClearDefaultHint.setVisibility(View.GONE);
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            // ignore
         }
-        mAlwaysUse.setOnCheckedChangeListener(this);
-        mClearDefaultHint = (TextView)ap.mView.findViewById(
-                                                    com.android.internal.R.id.clearDefaultHint);
-        mClearDefaultHint.setVisibility(View.GONE);
 
         setupAlert();
 
     }
 
+    /**
+     * Can the app be the default for the USB device. I.e. can the app be launched by default if
+     * the device is plugged in.
+     *
+     * @param device The device the app would be default for
+     * @param packageInfo The package info of the app
+     *
+     * @return {@code true} iff the app can be default
+     */
+    private boolean canBeDefault(@NonNull UsbDevice device, @NonNull PackageInfo packageInfo) {
+        ActivityInfo[] activities = packageInfo.activities;
+        if (activities != null) {
+            int numActivities = activities.length;
+            for (int i = 0; i < numActivities; i++) {
+                ActivityInfo activityInfo = activities[i];
+
+                try (XmlResourceParser parser = activityInfo.loadXmlMetaData(getPackageManager(),
+                        UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
+                    if (parser == null) {
+                        continue;
+                    }
+
+                    XmlUtils.nextElement(parser);
+                    while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+                        if ("usb-device".equals(parser.getName())) {
+                            DeviceFilter filter = DeviceFilter.read(parser);
+                            if (filter.matches(device)) {
+                                return true;
+                            }
+                        }
+
+                        XmlUtils.nextElement(parser);
+                    }
+                } catch (Exception e) {
+                    Log.w(TAG, "Unable to load component info " + activityInfo.toString(), e);
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Can the app be the default for the USB accessory. I.e. can the app be launched by default if
+     * the accessory is plugged in.
+     *
+     * @param accessory The accessory the app would be default for
+     * @param packageInfo The package info of the app
+     *
+     * @return {@code true} iff the app can be default
+     */
+    private boolean canBeDefault(@NonNull UsbAccessory accessory,
+            @NonNull PackageInfo packageInfo) {
+        ActivityInfo[] activities = packageInfo.activities;
+        if (activities != null) {
+            int numActivities = activities.length;
+            for (int i = 0; i < numActivities; i++) {
+                ActivityInfo activityInfo = activities[i];
+
+                try (XmlResourceParser parser = activityInfo.loadXmlMetaData(getPackageManager(),
+                        UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
+                    if (parser == null) {
+                        continue;
+                    }
+
+                    XmlUtils.nextElement(parser);
+                    while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+                        if ("usb-accessory".equals(parser.getName())) {
+                            AccessoryFilter filter = AccessoryFilter.read(parser);
+                            if (filter.matches(accessory)) {
+                                return true;
+                            }
+                        }
+
+                        XmlUtils.nextElement(parser);
+                    }
+                } catch (Exception e) {
+                    Log.w(TAG, "Unable to load component info " + activityInfo.toString(), e);
+                }
+            }
+        }
+
+        return false;
+    }
+
     @Override
     public void onDestroy() {
         IBinder b = ServiceManager.getService(USB_SERVICE);
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index ebb5a62..917e651 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -32,9 +32,10 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.res.XmlResourceParser;
+import android.hardware.usb.AccessoryFilter;
+import android.hardware.usb.DeviceFilter;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbInterface;
 import android.hardware.usb.UsbManager;
 import android.os.AsyncTask;
 import android.os.Environment;
@@ -58,7 +59,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -71,7 +71,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 
 class UsbProfileGroupSettingsManager {
     private static final String TAG = UsbProfileGroupSettingsManager.class.getSimpleName();
@@ -157,404 +156,6 @@
         }
     }
 
-    // This class is used to describe a USB device.
-    // When used in HashMaps all values must be specified,
-    // but wildcards can be used for any of the fields in
-    // the package meta-data.
-    private static class DeviceFilter {
-        // USB Vendor ID (or -1 for unspecified)
-        public final int mVendorId;
-        // USB Product ID (or -1 for unspecified)
-        public final int mProductId;
-        // USB device or interface class (or -1 for unspecified)
-        public final int mClass;
-        // USB device subclass (or -1 for unspecified)
-        public final int mSubclass;
-        // USB device protocol (or -1 for unspecified)
-        public final int mProtocol;
-        // USB device manufacturer name string (or null for unspecified)
-        public final String mManufacturerName;
-        // USB device product name string (or null for unspecified)
-        public final String mProductName;
-        // USB device serial number string (or null for unspecified)
-        public final String mSerialNumber;
-
-        public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol,
-                            String manufacturer, String product, String serialnum) {
-            mVendorId = vid;
-            mProductId = pid;
-            mClass = clasz;
-            mSubclass = subclass;
-            mProtocol = protocol;
-            mManufacturerName = manufacturer;
-            mProductName = product;
-            mSerialNumber = serialnum;
-        }
-
-        public DeviceFilter(UsbDevice device) {
-            mVendorId = device.getVendorId();
-            mProductId = device.getProductId();
-            mClass = device.getDeviceClass();
-            mSubclass = device.getDeviceSubclass();
-            mProtocol = device.getDeviceProtocol();
-            mManufacturerName = device.getManufacturerName();
-            mProductName = device.getProductName();
-            mSerialNumber = device.getSerialNumber();
-        }
-
-        public static DeviceFilter read(XmlPullParser parser)
-                throws XmlPullParserException, IOException {
-            int vendorId = -1;
-            int productId = -1;
-            int deviceClass = -1;
-            int deviceSubclass = -1;
-            int deviceProtocol = -1;
-            String manufacturerName = null;
-            String productName = null;
-            String serialNumber = null;
-
-            int count = parser.getAttributeCount();
-            for (int i = 0; i < count; i++) {
-                String name = parser.getAttributeName(i);
-                String value = parser.getAttributeValue(i);
-                // Attribute values are ints or strings
-                if ("manufacturer-name".equals(name)) {
-                    manufacturerName = value;
-                } else if ("product-name".equals(name)) {
-                    productName = value;
-                } else if ("serial-number".equals(name)) {
-                    serialNumber = value;
-                } else {
-                    int intValue;
-                    int radix = 10;
-                    if (value != null && value.length() > 2 && value.charAt(0) == '0' &&
-                        (value.charAt(1) == 'x' || value.charAt(1) == 'X')) {
-                        // allow hex values starting with 0x or 0X
-                        radix = 16;
-                        value = value.substring(2);
-                    }
-                    try {
-                        intValue = Integer.parseInt(value, radix);
-                    } catch (NumberFormatException e) {
-                        Slog.e(TAG, "invalid number for field " + name, e);
-                        continue;
-                    }
-                    if ("vendor-id".equals(name)) {
-                        vendorId = intValue;
-                    } else if ("product-id".equals(name)) {
-                        productId = intValue;
-                    } else if ("class".equals(name)) {
-                        deviceClass = intValue;
-                    } else if ("subclass".equals(name)) {
-                        deviceSubclass = intValue;
-                    } else if ("protocol".equals(name)) {
-                        deviceProtocol = intValue;
-                    }
-                }
-            }
-            return new DeviceFilter(vendorId, productId,
-                    deviceClass, deviceSubclass, deviceProtocol,
-                    manufacturerName, productName, serialNumber);
-        }
-
-        public void write(XmlSerializer serializer) throws IOException {
-            serializer.startTag(null, "usb-device");
-            if (mVendorId != -1) {
-                serializer.attribute(null, "vendor-id", Integer.toString(mVendorId));
-            }
-            if (mProductId != -1) {
-                serializer.attribute(null, "product-id", Integer.toString(mProductId));
-            }
-            if (mClass != -1) {
-                serializer.attribute(null, "class", Integer.toString(mClass));
-            }
-            if (mSubclass != -1) {
-                serializer.attribute(null, "subclass", Integer.toString(mSubclass));
-            }
-            if (mProtocol != -1) {
-                serializer.attribute(null, "protocol", Integer.toString(mProtocol));
-            }
-            if (mManufacturerName != null) {
-                serializer.attribute(null, "manufacturer-name", mManufacturerName);
-            }
-            if (mProductName != null) {
-                serializer.attribute(null, "product-name", mProductName);
-            }
-            if (mSerialNumber != null) {
-                serializer.attribute(null, "serial-number", mSerialNumber);
-            }
-            serializer.endTag(null, "usb-device");
-        }
-
-        private boolean matches(int clasz, int subclass, int protocol) {
-            return ((mClass == -1 || clasz == mClass) &&
-                    (mSubclass == -1 || subclass == mSubclass) &&
-                    (mProtocol == -1 || protocol == mProtocol));
-        }
-
-        public boolean matches(UsbDevice device) {
-            if (mVendorId != -1 && device.getVendorId() != mVendorId) return false;
-            if (mProductId != -1 && device.getProductId() != mProductId) return false;
-            if (mManufacturerName != null && device.getManufacturerName() == null) return false;
-            if (mProductName != null && device.getProductName() == null) return false;
-            if (mSerialNumber != null && device.getSerialNumber() == null) return false;
-            if (mManufacturerName != null && device.getManufacturerName() != null &&
-                !mManufacturerName.equals(device.getManufacturerName())) return false;
-            if (mProductName != null && device.getProductName() != null &&
-                !mProductName.equals(device.getProductName())) return false;
-            if (mSerialNumber != null && device.getSerialNumber() != null &&
-                !mSerialNumber.equals(device.getSerialNumber())) return false;
-
-            // check device class/subclass/protocol
-            if (matches(device.getDeviceClass(), device.getDeviceSubclass(),
-                    device.getDeviceProtocol())) return true;
-
-            // if device doesn't match, check the interfaces
-            int count = device.getInterfaceCount();
-            for (int i = 0; i < count; i++) {
-                UsbInterface intf = device.getInterface(i);
-                 if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
-                        intf.getInterfaceProtocol())) return true;
-            }
-
-            return false;
-        }
-
-        /**
-         * If the device described by {@code device} covered by this filter?
-         *
-         * @param device The device
-         *
-         * @return {@code true} iff this filter covers the {@code device}
-         */
-        public boolean contains(DeviceFilter device) {
-            // -1 and null means "match anything"
-
-            if (mVendorId != -1 && device.mVendorId != mVendorId) return false;
-            if (mProductId != -1 && device.mProductId != mProductId) return false;
-            if (mManufacturerName != null && !Objects.equals(mManufacturerName,
-                    device.mManufacturerName)) {
-                return false;
-            }
-            if (mProductName != null && !Objects.equals(mProductName, device.mProductName)) {
-                return false;
-            }
-            if (mSerialNumber != null
-                    && !Objects.equals(mSerialNumber, device.mSerialNumber)) {
-                return false;
-            }
-
-            // check device class/subclass/protocol
-            return matches(device.mClass, device.mSubclass, device.mProtocol);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            // can't compare if we have wildcard strings
-            if (mVendorId == -1 || mProductId == -1 ||
-                    mClass == -1 || mSubclass == -1 || mProtocol == -1) {
-                return false;
-            }
-            if (obj instanceof DeviceFilter) {
-                DeviceFilter filter = (DeviceFilter)obj;
-
-                if (filter.mVendorId != mVendorId ||
-                        filter.mProductId != mProductId ||
-                        filter.mClass != mClass ||
-                        filter.mSubclass != mSubclass ||
-                        filter.mProtocol != mProtocol) {
-                    return(false);
-                }
-                if ((filter.mManufacturerName != null &&
-                        mManufacturerName == null) ||
-                    (filter.mManufacturerName == null &&
-                        mManufacturerName != null) ||
-                    (filter.mProductName != null &&
-                        mProductName == null)  ||
-                    (filter.mProductName == null &&
-                        mProductName != null) ||
-                    (filter.mSerialNumber != null &&
-                        mSerialNumber == null)  ||
-                    (filter.mSerialNumber == null &&
-                        mSerialNumber != null)) {
-                    return(false);
-                }
-                if  ((filter.mManufacturerName != null &&
-                        mManufacturerName != null &&
-                        !mManufacturerName.equals(filter.mManufacturerName)) ||
-                     (filter.mProductName != null &&
-                        mProductName != null &&
-                        !mProductName.equals(filter.mProductName)) ||
-                     (filter.mSerialNumber != null &&
-                        mSerialNumber != null &&
-                        !mSerialNumber.equals(filter.mSerialNumber))) {
-                    return false;
-                }
-                return true;
-            }
-            if (obj instanceof UsbDevice) {
-                UsbDevice device = (UsbDevice)obj;
-                if (device.getVendorId() != mVendorId ||
-                        device.getProductId() != mProductId ||
-                        device.getDeviceClass() != mClass ||
-                        device.getDeviceSubclass() != mSubclass ||
-                        device.getDeviceProtocol() != mProtocol) {
-                    return(false);
-                }
-                if ((mManufacturerName != null && device.getManufacturerName() == null) ||
-                        (mManufacturerName == null && device.getManufacturerName() != null) ||
-                        (mProductName != null && device.getProductName() == null) ||
-                        (mProductName == null && device.getProductName() != null) ||
-                        (mSerialNumber != null && device.getSerialNumber() == null) ||
-                        (mSerialNumber == null && device.getSerialNumber() != null)) {
-                    return(false);
-                }
-                if ((device.getManufacturerName() != null &&
-                        !mManufacturerName.equals(device.getManufacturerName())) ||
-                        (device.getProductName() != null &&
-                            !mProductName.equals(device.getProductName())) ||
-                        (device.getSerialNumber() != null &&
-                            !mSerialNumber.equals(device.getSerialNumber()))) {
-                    return false;
-                }
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            return (((mVendorId << 16) | mProductId) ^
-                    ((mClass << 16) | (mSubclass << 8) | mProtocol));
-        }
-
-        @Override
-        public String toString() {
-            return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId +
-                    ",mClass=" + mClass + ",mSubclass=" + mSubclass +
-                    ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName +
-                    ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber +
-                    "]";
-        }
-    }
-
-    // This class is used to describe a USB accessory.
-    // When used in HashMaps all values must be specified,
-    // but wildcards can be used for any of the fields in
-    // the package meta-data.
-    private static class AccessoryFilter {
-        // USB accessory manufacturer (or null for unspecified)
-        public final String mManufacturer;
-        // USB accessory model (or null for unspecified)
-        public final String mModel;
-        // USB accessory version (or null for unspecified)
-        public final String mVersion;
-
-        public AccessoryFilter(String manufacturer, String model, String version) {
-            mManufacturer = manufacturer;
-            mModel = model;
-            mVersion = version;
-        }
-
-        public AccessoryFilter(UsbAccessory accessory) {
-            mManufacturer = accessory.getManufacturer();
-            mModel = accessory.getModel();
-            mVersion = accessory.getVersion();
-        }
-
-        public static AccessoryFilter read(XmlPullParser parser)
-                throws XmlPullParserException, IOException {
-            String manufacturer = null;
-            String model = null;
-            String version = null;
-
-            int count = parser.getAttributeCount();
-            for (int i = 0; i < count; i++) {
-                String name = parser.getAttributeName(i);
-                String value = parser.getAttributeValue(i);
-
-                if ("manufacturer".equals(name)) {
-                    manufacturer = value;
-                } else if ("model".equals(name)) {
-                    model = value;
-                } else if ("version".equals(name)) {
-                    version = value;
-                }
-             }
-             return new AccessoryFilter(manufacturer, model, version);
-        }
-
-        public void write(XmlSerializer serializer)throws IOException {
-            serializer.startTag(null, "usb-accessory");
-            if (mManufacturer != null) {
-                serializer.attribute(null, "manufacturer", mManufacturer);
-            }
-            if (mModel != null) {
-                serializer.attribute(null, "model", mModel);
-            }
-            if (mVersion != null) {
-                serializer.attribute(null, "version", mVersion);
-            }
-            serializer.endTag(null, "usb-accessory");
-        }
-
-        public boolean matches(UsbAccessory acc) {
-            if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
-            if (mModel != null && !acc.getModel().equals(mModel)) return false;
-            return !(mVersion != null && !acc.getVersion().equals(mVersion));
-        }
-
-        /**
-         * Is the accessories described {@code accessory} covered by this filter?
-         *
-         * @param accessory A filter describing the accessory
-         *
-         * @return {@code true} iff this the filter covers the accessory
-         */
-        public boolean contains(AccessoryFilter accessory) {
-            if (mManufacturer != null && !Objects.equals(accessory.mManufacturer, mManufacturer)) {
-                return false;
-            }
-            if (mModel != null && !Objects.equals(accessory.mModel, mModel)) return false;
-            return !(mVersion != null && !Objects.equals(accessory.mVersion, mVersion));
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            // can't compare if we have wildcard strings
-            if (mManufacturer == null || mModel == null || mVersion == null) {
-                return false;
-            }
-            if (obj instanceof AccessoryFilter) {
-                AccessoryFilter filter = (AccessoryFilter)obj;
-                return (mManufacturer.equals(filter.mManufacturer) &&
-                        mModel.equals(filter.mModel) &&
-                        mVersion.equals(filter.mVersion));
-            }
-            if (obj instanceof UsbAccessory) {
-                UsbAccessory accessory = (UsbAccessory)obj;
-                return (mManufacturer.equals(accessory.getManufacturer()) &&
-                        mModel.equals(accessory.getModel()) &&
-                        mVersion.equals(accessory.getVersion()));
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
-                    (mModel == null ? 0 : mModel.hashCode()) ^
-                    (mVersion == null ? 0 : mVersion.hashCode()));
-        }
-
-        @Override
-        public String toString() {
-            return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
-                                "\", mModel=\"" + mModel +
-                                "\", mVersion=\"" + mVersion + "\"]";
-        }
-    }
-
     private class MyPackageMonitor extends PackageMonitor {
         @Override
         public void onPackageAdded(String packageName, int uid) {
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index b9ae654..b214d21 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -345,15 +345,14 @@
       *out << "# Referenced at " << location.source << "\n";
     }
     if (keep_set.conditional_keep_rules_ && can_be_conditional) {
-      *out << "-keep class " << entry.first << " {\n  ifused class **.R$layout {\n";
+      *out << "-if class **.R$layout {\n";
       for (const UsageLocation& location : locations) {
         auto transformed_name = JavaClassGenerator::TransformToFieldName(location.name.entry);
-        *out << "    int " << transformed_name << ";\n";
+        *out << "  int " << transformed_name << ";\n";
       }
-      *out << "  };\n  <init>(...);\n}\n" << std::endl;
-    } else {
-      *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
+      *out << "}\n";
     }
+    *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
   }
 
   for (const auto& entry : keep_set.method_set_) {
diff --git a/tools/aapt2/java/ProguardRules_test.cpp b/tools/aapt2/java/ProguardRules_test.cpp
index df3ac8b..802c56a 100644
--- a/tools/aapt2/java/ProguardRules_test.cpp
+++ b/tools/aapt2/java/ProguardRules_test.cpp
@@ -130,7 +130,7 @@
   ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
 
   std::string actual = out.str();
-  EXPECT_THAT(actual, HasSubstr("ifused class **.R$layout"));
+  EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
   EXPECT_THAT(actual, HasSubstr("int foo"));
   EXPECT_THAT(actual, HasSubstr("int bar"));
   EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
@@ -152,7 +152,7 @@
   ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
 
   std::string actual = out.str();
-  EXPECT_THAT(actual, HasSubstr("ifused class **.R$layout"));
+  EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
   EXPECT_THAT(actual, HasSubstr("int foo"));
   EXPECT_THAT(actual, HasSubstr("int bar"));
   EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
@@ -174,7 +174,7 @@
   ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
 
   std::string actual = out.str();
-  EXPECT_THAT(actual, Not(HasSubstr("ifused")));
+  EXPECT_THAT(actual, Not(HasSubstr("-if")));
 }
 
 TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {