Merge "Audio: Add ENCODING_DTS_HD_MA, ENCODING_DTS_UHD_P2"
diff --git a/ApiDocs.bp b/ApiDocs.bp
index bf3a6a3..a46ecce 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -183,6 +183,7 @@
 /////////////////////////////////////////////////////////////////////
 
 framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " +
+    "-metalavaApiSince " +
     "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
     "-overview $(location core/java/overview.html) " +
     // Federate Support Library references against local API file.
@@ -374,7 +375,7 @@
     ],
     proofread_file: "ds-docs-proofread.txt",
     args: framework_docs_only_args +
-        " -toroot / -yamlV2 -metalavaApiSince -samplegroup Admin " +
+        " -toroot / -yamlV2 -samplegroup Admin " +
         " -samplegroup Background " +
         " -samplegroup Connectivity " +
         " -samplegroup Content " +
diff --git a/core/api/current.txt b/core/api/current.txt
index 1608616..01bfecf 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -27357,6 +27357,15 @@
 
 package android.nfc {
 
+  public final class AvailableNfcAntenna implements android.os.Parcelable {
+    ctor public AvailableNfcAntenna(int, int);
+    method public int describeContents();
+    method public int getLocationX();
+    method public int getLocationY();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.nfc.AvailableNfcAntenna> CREATOR;
+  }
+
   public class FormatException extends java.lang.Exception {
     ctor public FormatException();
     ctor public FormatException(String);
@@ -27418,6 +27427,7 @@
     method @Deprecated public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
     method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
+    method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo();
     method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
     method @Deprecated public boolean invokeBeam(android.app.Activity);
     method public boolean isEnabled();
@@ -27480,6 +27490,17 @@
     method public void onTagDiscovered(android.nfc.Tag);
   }
 
+  public final class NfcAntennaInfo implements android.os.Parcelable {
+    ctor public NfcAntennaInfo(int, int, boolean, @NonNull java.util.List<android.nfc.AvailableNfcAntenna>);
+    method public int describeContents();
+    method @NonNull public java.util.List<android.nfc.AvailableNfcAntenna> getAvailableNfcAntennas();
+    method public int getDeviceHeight();
+    method public int getDeviceWidth();
+    method public boolean isDeviceFoldable();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NfcAntennaInfo> CREATOR;
+  }
+
   public final class NfcEvent {
     field public final android.nfc.NfcAdapter nfcAdapter;
     field public final int peerLlcpMajorVersion;
diff --git a/core/java/Android.bp b/core/java/Android.bp
index cf30e31..eac8b9b 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -485,3 +485,9 @@
 }
 
 // protolog end
+
+// temporary placeholder until the real module is available
+java_library {
+    name: "framework-configinfrastructure",
+    sdk_version: "module_current",
+}
diff --git a/core/java/android/content/integrity/AppInstallMetadata.java b/core/java/android/content/integrity/AppInstallMetadata.java
index 9874890..91b0007 100644
--- a/core/java/android/content/integrity/AppInstallMetadata.java
+++ b/core/java/android/content/integrity/AppInstallMetadata.java
@@ -129,9 +129,18 @@
     @Override
     public String toString() {
         return String.format(
-                "AppInstallMetadata { PackageName = %s, AppCerts = %s, InstallerName = %s,"
-                    + " InstallerCerts = %s, VersionCode = %d, PreInstalled = %b, StampPresent ="
-                    + " %b, StampVerified = %b, StampTrusted = %b, StampCert = %s }",
+                "AppInstallMetadata {"
+                    + " PackageName = %s,"
+                    + " AppCerts = %s,"
+                    + " AppCertsLineage = %s,"
+                    + " InstallerName = %s,"
+                    + " InstallerCerts = %s,"
+                    + " VersionCode = %d,"
+                    + " PreInstalled = %b,"
+                    + " StampPresent = %b,"
+                    + " StampVerified = %b,"
+                    + " StampTrusted = %b,"
+                    + " StampCert = %s }",
                 mPackageName,
                 mAppCertificates,
                 mAppCertificateLineage,
diff --git a/core/java/android/hardware/radio/Announcement.java b/core/java/android/hardware/radio/Announcement.java
index 8febed3..bab4153 100644
--- a/core/java/android/hardware/radio/Announcement.java
+++ b/core/java/android/hardware/radio/Announcement.java
@@ -86,7 +86,7 @@
     public Announcement(@NonNull ProgramSelector selector, @Type int type,
             @NonNull Map<String, String> vendorInfo) {
         mSelector = Objects.requireNonNull(selector);
-        mType = Objects.requireNonNull(type);
+        mType = type;
         mVendorInfo = Objects.requireNonNull(vendorInfo);
     }
 
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 40e4083..3a7aea5 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -104,12 +104,23 @@
 
     // TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz
 
+    /**
+     * Key for transports that need to be marked as restricted by the VCN
+     *
+     * <p>Defaults to TRANSPORT_WIFI if the config does not exist
+     *
+     * @hide
+     */
+    public static final String VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY =
+            "vcn_restricted_transports";
+
     /** List of Carrier Config options to extract from Carrier Config bundles. @hide */
     @NonNull
     public static final String[] VCN_RELATED_CARRIER_CONFIG_KEYS =
             new String[] {
                 VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
-                VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY
+                VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
+                VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY
             };
 
     private static final Map<
diff --git a/core/java/android/nfc/AvailableNfcAntenna.aidl b/core/java/android/nfc/AvailableNfcAntenna.aidl
new file mode 100644
index 0000000..9d06e2d
--- /dev/null
+++ b/core/java/android/nfc/AvailableNfcAntenna.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013 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.nfc;
+
+parcelable AvailableNfcAntenna;
diff --git a/core/java/android/nfc/AvailableNfcAntenna.java b/core/java/android/nfc/AvailableNfcAntenna.java
new file mode 100644
index 0000000..946ba67
--- /dev/null
+++ b/core/java/android/nfc/AvailableNfcAntenna.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a single available Nfc antenna
+ * on an Android device.
+ */
+public final class AvailableNfcAntenna implements Parcelable {
+    /**
+     * Location on the antenna on the Y axis in millimeters.
+     * 0 is the bottom-left when the user is facing the screen.
+     */
+    private final int mLocationX;
+    /**
+     * Location on the antenna on the Y axis in millimeters.
+     * 0 is the bottom-left when the user is facing the screen.
+     */
+    private final int mLocationY;
+
+    public AvailableNfcAntenna(int locationX, int locationY) {
+        this.mLocationX = locationX;
+        this.mLocationY = locationY;
+    }
+
+    /**
+     * Location on the antenna on the X axis in millimeters.
+     * 0 is the bottom-left when the user is facing the screen.
+     */
+    public int getLocationX() {
+        return mLocationX;
+    }
+
+    /**
+     * Location on the antenna on the Y axis in millimeters.
+     * 0 is the bottom-left when the user is facing the screen.
+     */
+    public int getLocationY() {
+        return mLocationY;
+    }
+
+    private AvailableNfcAntenna(Parcel in) {
+        this.mLocationX = in.readInt();
+        this.mLocationY = in.readInt();
+    }
+
+    public static final @android.annotation.NonNull Parcelable.Creator<AvailableNfcAntenna>
+            CREATOR = new Parcelable.Creator<AvailableNfcAntenna>() {
+                @Override
+                public AvailableNfcAntenna createFromParcel(Parcel in) {
+                    return new AvailableNfcAntenna(in);
+                }
+
+                @Override
+                public AvailableNfcAntenna[] newArray(int size) {
+                    return new AvailableNfcAntenna[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mLocationX);
+        dest.writeInt(mLocationY);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mLocationX;
+        result = prime * result + mLocationY;
+        return result;
+    }
+
+    /**
+     * Returns true if the specified AvailableNfcAntenna contains
+     * identical specifications.
+     */
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        AvailableNfcAntenna other = (AvailableNfcAntenna) obj;
+        if (this.mLocationX != other.mLocationX) return false;
+        return this.mLocationY == other.mLocationY;
+    }
+
+    @Override
+    public String toString() {
+        return "AvailableNfcAntenna " + "x: " + mLocationX + " y: " + mLocationY;
+    }
+}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index cb9a3e4..de107a2 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -31,6 +31,7 @@
 import android.nfc.INfcUnlockHandler;
 import android.nfc.ITagRemovedCallback;
 import android.nfc.INfcDta;
+import android.nfc.NfcAntennaInfo;
 import android.os.Bundle;
 
 /**
@@ -72,6 +73,7 @@
     boolean isNfcSecureEnabled();
     boolean deviceSupportsNfcSecure();
     boolean setNfcSecure(boolean enable);
+    NfcAntennaInfo getNfcAntennaInfo();
 
     boolean setControllerAlwaysOn(boolean value);
     boolean isControllerAlwaysOn();
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 3282d56..f545c30 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -18,6 +18,7 @@
 
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -1854,6 +1855,36 @@
     }
 
     /**
+     * Returns information regarding Nfc antennas on the device
+     * such as their relative positioning on the device.
+     *
+     * @return Information on the nfc antenna(s) on the device.
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     */
+    @Nullable
+    public NfcAntennaInfo getNfcAntennaInfo() {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.getNfcAntennaInfo();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return null;
+            }
+            try {
+                return sService.getNfcAntennaInfo();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return null;
+        }
+    }
+
+    /**
      * Checks Secure NFC feature is enabled.
      *
      * @return True if Secure NFC is enabled, false otherwise
diff --git a/core/java/android/nfc/NfcAntennaInfo.aidl b/core/java/android/nfc/NfcAntennaInfo.aidl
new file mode 100644
index 0000000..d5e79fc
--- /dev/null
+++ b/core/java/android/nfc/NfcAntennaInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013 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.nfc;
+
+parcelable NfcAntennaInfo;
diff --git a/core/java/android/nfc/NfcAntennaInfo.java b/core/java/android/nfc/NfcAntennaInfo.java
new file mode 100644
index 0000000..d54fcd2
--- /dev/null
+++ b/core/java/android/nfc/NfcAntennaInfo.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Contains information on all available Nfc
+ * antennas on an Android device as well as information
+ * on the device itself in relation positioning of the
+ * antennas.
+ */
+public final class NfcAntennaInfo implements Parcelable {
+    // Width of the device in millimeters.
+    private final int mDeviceWidth;
+    // Height of the device in millimeters.
+    private final int mDeviceHeight;
+    // Whether the device is foldable.
+    private final boolean mDeviceFoldable;
+    // All available Nfc Antennas on the device.
+    private final List<AvailableNfcAntenna> mAvailableNfcAntennas;
+
+    public NfcAntennaInfo(int deviceWidth, int deviceHeight, boolean deviceFoldable,
+            @NonNull List<AvailableNfcAntenna> availableNfcAntennas) {
+        this.mDeviceWidth = deviceWidth;
+        this.mDeviceHeight = deviceHeight;
+        this.mDeviceFoldable = deviceFoldable;
+        this.mAvailableNfcAntennas = availableNfcAntennas;
+    }
+
+    /**
+     * Width of the device in millimeters.
+     */
+    public int getDeviceWidth() {
+        return mDeviceWidth;
+    }
+
+    /**
+     * Height of the device in millimeters.
+     */
+    public int getDeviceHeight() {
+        return mDeviceHeight;
+    }
+
+    /**
+     * Whether the device is foldable. When the device is foldable,
+     * the 0, 0 is considered to be bottom-left when the device is unfolded and
+     * the screens are facing the user. For non-foldable devices 0, 0
+     * is bottom-left when the user is facing the screen.
+     */
+    public boolean isDeviceFoldable() {
+        return mDeviceFoldable;
+    }
+
+    /**
+     * Get all NFC antennas that exist on the device.
+     */
+    @NonNull
+    public List<AvailableNfcAntenna> getAvailableNfcAntennas() {
+        return mAvailableNfcAntennas;
+    }
+
+    private NfcAntennaInfo(Parcel in) {
+        this.mDeviceWidth = in.readInt();
+        this.mDeviceHeight = in.readInt();
+        this.mDeviceFoldable = in.readByte() != 0;
+        this.mAvailableNfcAntennas = new ArrayList<>();
+        in.readParcelableList(this.mAvailableNfcAntennas,
+                AvailableNfcAntenna.class.getClassLoader());
+    }
+
+    public static final @NonNull Parcelable.Creator<NfcAntennaInfo> CREATOR =
+            new Parcelable.Creator<NfcAntennaInfo>() {
+        @Override
+        public NfcAntennaInfo createFromParcel(Parcel in) {
+            return new NfcAntennaInfo(in);
+        }
+
+        @Override
+        public NfcAntennaInfo[] newArray(int size) {
+            return new NfcAntennaInfo[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mDeviceWidth);
+        dest.writeInt(mDeviceHeight);
+        dest.writeByte((byte) (mDeviceFoldable ? 1 : 0));
+        dest.writeTypedList(mAvailableNfcAntennas, 0);
+    }
+}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 3d10661..0f3ed19 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -328,16 +328,28 @@
     public static final native boolean isDirectlyHandlingTransaction();
 
     /**
+    * Returns {@code true} if the current thread has had its identity
+    * set explicitly via {@link #clearCallingIdentity()}
+    *
+    * @hide
+    */
+    @CriticalNative
+    private static native boolean hasExplicitIdentity();
+
+    /**
      * Return the Linux UID assigned to the process that sent the transaction
      * currently being processed.
      *
      * @throws IllegalStateException if the current thread is not currently
-     * executing an incoming transaction.
+     * executing an incoming transaction and the calling identity has not been
+     * explicitly set with {@link #clearCallingIdentity()}
      */
     public static final int getCallingUidOrThrow() {
-        if (!isDirectlyHandlingTransaction()) {
+        if (!isDirectlyHandlingTransaction() && !hasExplicitIdentity()) {
             throw new IllegalStateException(
-                  "Thread is not in a binder transcation");
+                  "Thread is not in a binder transaction, "
+                  + "and the calling identity has not been "
+                  + "explicitly set with clearCallingIdentity");
         }
         return getCallingUid();
     }
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 9f39c32..53594e1 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -29,7 +29,7 @@
 per-file android_util_AssetManager* = file:/core/java/android/content/res/OWNERS
 per-file android_util_StringBlock* = file:/core/java/android/content/res/OWNERS
 per-file android_util_XmlBlock* = file:/core/java/android/content/res/OWNERS
-per-file com_android_internal_content_om_OverlayConfig* = file:/core/java/android/content/res/OWNERS
+per-file com_android_internal_content_om_Overlay* = file:/core/java/android/content/res/OWNERS
 
 # Binder related things
 per-file android_os_Parcel* = file:platform/frameworks/native:/libs/binder/OWNERS
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 01837f4..a7c7d0b 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -983,6 +983,10 @@
     IPCThreadState::self()->restoreCallingIdentity(token);
 }
 
+static jboolean android_os_Binder_hasExplicitIdentity() {
+    return IPCThreadState::self()->hasExplicitIdentity();
+}
+
 static void android_os_Binder_setThreadStrictModePolicy(jint policyMask)
 {
     IPCThreadState::self()->setStrictModePolicy(policyMask);
@@ -1079,6 +1083,8 @@
     // @CriticalNative
     { "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
     // @CriticalNative
+    { "hasExplicitIdentity", "()Z", (void*)android_os_Binder_hasExplicitIdentity },
+    // @CriticalNative
     { "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy },
     // @CriticalNative
     { "getThreadStrictModePolicy", "()I", (void*)android_os_Binder_getThreadStrictModePolicy },
diff --git a/core/tests/coretests/src/android/os/BinderTest.java b/core/tests/coretests/src/android/os/BinderTest.java
index 99dbe64..02f8790 100644
--- a/core/tests/coretests/src/android/os/BinderTest.java
+++ b/core/tests/coretests/src/android/os/BinderTest.java
@@ -20,6 +20,8 @@
 
 import junit.framework.TestCase;
 
+import static org.testng.Assert.assertThrows;
+
 public class BinderTest extends TestCase {
     private static final int UID = 100;
 
@@ -45,12 +47,8 @@
     }
 
     @SmallTest
-    public void testGetCallingUidOrThrow() throws Exception {
-        try {
-            Binder.getCallingUidOrThrow();
-            throw new AssertionError("IllegalStateException expected");
-        } catch (IllegalStateException expected) {
-        }
+    public void testGetCallingUidOrThrow_throws() throws Exception {
+        assertThrows(IllegalStateException.class, () -> Binder.getCallingUidOrThrow());
     }
 
     @SmallTest
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index c81473d..8e7c6a8 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -363,6 +363,7 @@
 # key 413 "KEY_DIGITS"
 # key 414 "KEY_TEEN"
 # key 415 "KEY_TWEN"
+key 528 FOCUS
 
 key 429   CONTACTS
 
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 62d14e1..659aafe 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -3751,6 +3751,11 @@
                 // Skip input stream to the end of the EXIF chunk
                 totalInputStream.skipBytes(WEBP_CHUNK_TYPE_BYTE_LENGTH);
                 int exifChunkLength = totalInputStream.readInt();
+                // RIFF chunks have a single padding byte at the end if the declared chunk size is
+                // odd.
+                if (exifChunkLength % 2 != 0) {
+                    exifChunkLength++;
+                }
                 totalInputStream.skipBytes(exifChunkLength);
 
                 // Write new EXIF chunk to output stream
@@ -3821,7 +3826,7 @@
                     int widthAndHeight = 0;
                     int width = 0;
                     int height = 0;
-                    int alpha = 0;
+                    boolean alpha = false;
                     // Save VP8 frame data for later
                     byte[] vp8Frame = new byte[3];
 
@@ -3856,7 +3861,7 @@
                         width = ((widthAndHeight << 18) >> 18) + 1;
                         height = ((widthAndHeight << 4) >> 18) + 1;
                         // Retrieve alpha bit
-                        alpha = widthAndHeight & (1 << 3);
+                        alpha = (widthAndHeight & (1 << 28)) != 0;
                         bytesToRead -= (1 /* VP8L signature */ + 4);
                     }
 
@@ -3864,10 +3869,12 @@
                     nonHeaderOutputStream.write(WEBP_CHUNK_TYPE_VP8X);
                     nonHeaderOutputStream.writeInt(WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH);
                     byte[] data = new byte[WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH];
+                    // ALPHA flag
+                    if (alpha) {
+                        data[0] = (byte) (data[0] | (1 << 4));
+                    }
                     // EXIF flag
                     data[0] = (byte) (data[0] | (1 << 3));
-                    // ALPHA flag
-                    data[0] = (byte) (data[0] | (alpha << 4));
                     // VP8X stores Width - 1 and Height - 1 values
                     width -= 1;
                     height -= 1;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
index 195df78..006f4e9 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
@@ -23,6 +23,7 @@
 import android.graphics.BitmapFactory;
 import android.media.ExifInterface;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.test.AndroidTestCase;
 import android.util.Log;
 import android.system.ErrnoException;
@@ -37,6 +38,8 @@
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Objects;
 
 import libcore.io.IoUtils;
 import libcore.io.Streams;
@@ -353,20 +356,23 @@
         }
     }
 
-    private void testSaveAttributes_withFileName(File imageFile, ExpectedValue expectedValue)
+    private void testSaveAttributes_withFileName(File srcFile, ExpectedValue expectedValue)
             throws IOException {
+        File imageFile = clone(srcFile);
         String verboseTag = imageFile.getName();
 
         ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
         exifInterface.saveAttributes();
         exifInterface = new ExifInterface(imageFile.getAbsolutePath());
         compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+        assertBitmapsEquivalent(srcFile, imageFile);
+        assertSecondSaveProducesSameSizeFile(imageFile);
 
         // Test for modifying one attribute.
+        exifInterface = new ExifInterface(imageFile.getAbsolutePath());
         String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
         exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
         exifInterface.saveAttributes();
-        exifInterface = new ExifInterface(imageFile.getAbsolutePath());
         assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
         // Restore the backup value.
         exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
@@ -481,4 +487,56 @@
         // Test if it is possible to parse the volantis generated JPEG smoothly.
         testExifInterfaceForJpeg(VOLANTIS_JPEG, R.array.volantis_jpg);
     }
+
+    /**
+     * Asserts that {@code expectedImageFile} and {@code actualImageFile} can be decoded by
+     * {@link BitmapFactory} and the results have the same width, height and MIME type.
+     *
+     * <p>This does not check the image itself for similarity/equality.
+     */
+    private void assertBitmapsEquivalent(File expectedImageFile, File actualImageFile) {
+        BitmapFactory.Options expectedOptions = new BitmapFactory.Options();
+        Bitmap expectedBitmap = Objects.requireNonNull(
+                BitmapFactory.decodeFile(expectedImageFile.getAbsolutePath(), expectedOptions));
+        BitmapFactory.Options actualOptions = new BitmapFactory.Options();
+        Bitmap actualBitmap = Objects.requireNonNull(
+                BitmapFactory.decodeFile(actualImageFile.getAbsolutePath(), actualOptions));
+
+        assertEquals(expectedOptions.outWidth, actualOptions.outWidth);
+        assertEquals(expectedOptions.outHeight, actualOptions.outHeight);
+        assertEquals(expectedOptions.outMimeType, actualOptions.outMimeType);
+        assertEquals(expectedBitmap.getWidth(), actualBitmap.getWidth());
+        assertEquals(expectedBitmap.getHeight(), actualBitmap.getHeight());
+    }
+
+    /**
+     * Asserts that saving the file the second time (without modifying any attributes) produces
+     * exactly the same length file as the first save. The first save (with no modifications) is
+     * expected to (possibly) change the file length because {@link ExifInterface} may move/reformat
+     * the Exif block within the file, but the second save should not make further modifications.
+     */
+    private void assertSecondSaveProducesSameSizeFile(File imageFileAfterOneSave)
+            throws IOException {
+        File imageFileAfterTwoSaves = clone(imageFileAfterOneSave);
+        ExifInterface exifInterface = new ExifInterface(imageFileAfterTwoSaves.getAbsolutePath());
+        exifInterface.saveAttributes();
+        if (imageFileAfterOneSave.getAbsolutePath().endsWith(".png")
+                || imageFileAfterOneSave.getAbsolutePath().endsWith(".webp")) {
+            // PNG and (some) WebP files are (surprisingly) modified between the first and second
+            // save (b/249097443), so we check the difference between second and third save instead.
+            File imageFileAfterThreeSaves = clone(imageFileAfterTwoSaves);
+            exifInterface = new ExifInterface(imageFileAfterThreeSaves.getAbsolutePath());
+            exifInterface.saveAttributes();
+            assertEquals(imageFileAfterTwoSaves.length(), imageFileAfterThreeSaves.length());
+        } else {
+            assertEquals(imageFileAfterOneSave.length(), imageFileAfterTwoSaves.length());
+        }
+    }
+
+    private static File clone(File original) throws IOException {
+        final File cloned =
+                File.createTempFile("tmp_", +System.nanoTime() + "_" + original.getName());
+        FileUtils.copyFileOrThrow(original, cloned);
+        return cloned;
+    }
 }
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 76cac93..61f7f30 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -18,8 +18,11 @@
 
 import static android.Manifest.permission.DUMP;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_TEST;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnGatewayConnectionConfig.ALLOWED_CAPABILITIES;
+import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
@@ -53,6 +56,7 @@
 import android.net.vcn.VcnUnderlyingNetworkPolicy;
 import android.net.wifi.WifiInfo;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -68,6 +72,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Log;
 import android.util.Slog;
@@ -83,6 +88,7 @@
 import com.android.server.vcn.VcnContext;
 import com.android.server.vcn.VcnNetworkProvider;
 import com.android.server.vcn.util.PersistableBundleUtils;
+import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -159,6 +165,9 @@
     private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5);
     private static final int LOCAL_LOG_LINE_COUNT = 512;
 
+    private static final Set<Integer> RESTRICTED_TRANSPORTS_DEFAULT =
+            Collections.singleton(TRANSPORT_WIFI);
+
     // Public for use in all other VCN classes
     @NonNull public static final LocalLog LOCAL_LOG = new LocalLog(LOCAL_LOG_LINE_COUNT);
 
@@ -361,6 +370,34 @@
         public LocationPermissionChecker newLocationPermissionChecker(@NonNull Context context) {
             return new LocationPermissionChecker(context);
         }
+
+        /** Gets the transports that need to be marked as restricted by the VCN */
+        public Set<Integer> getRestrictedTransports(
+                ParcelUuid subGrp, TelephonySubscriptionSnapshot lastSnapshot) {
+            if (!Build.IS_ENG && !Build.IS_USERDEBUG) {
+                return RESTRICTED_TRANSPORTS_DEFAULT;
+            }
+
+            final PersistableBundleWrapper carrierConfig =
+                    lastSnapshot.getCarrierConfigForSubGrp(subGrp);
+            if (carrierConfig == null) {
+                return RESTRICTED_TRANSPORTS_DEFAULT;
+            }
+
+            final int[] defaultValue =
+                    RESTRICTED_TRANSPORTS_DEFAULT.stream().mapToInt(i -> i).toArray();
+            final int[] restrictedTransportsArray =
+                    carrierConfig.getIntArray(
+                            VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+                            defaultValue);
+
+            // Convert to a boxed set
+            final Set<Integer> restrictedTransports = new ArraySet<>();
+            for (int transport : restrictedTransportsArray) {
+                restrictedTransports.add(transport);
+            }
+            return restrictedTransports;
+        }
     }
 
     /** Notifies the VcnManagementService that external dependencies can be set up. */
@@ -517,6 +554,7 @@
                     }
                 }
 
+                boolean needNotifyAllPolicyListeners = false;
                 // Schedule teardown of any VCN instances that have lost carrier privileges (after a
                 // delay)
                 for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) {
@@ -564,6 +602,10 @@
                     } else {
                         // If this VCN's status has not changed, update it with the new snapshot
                         entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);
+                        needNotifyAllPolicyListeners |=
+                                !Objects.equals(
+                                        oldSnapshot.getCarrierConfigForSubGrp(subGrp),
+                                        mLastSnapshot.getCarrierConfigForSubGrp(subGrp));
                     }
                 }
 
@@ -573,6 +615,10 @@
                         getSubGroupToSubIdMappings(mLastSnapshot);
                 if (!currSubGrpMappings.equals(oldSubGrpMappings)) {
                     garbageCollectAndWriteVcnConfigsLocked();
+                    needNotifyAllPolicyListeners = true;
+                }
+
+                if (needNotifyAllPolicyListeners) {
                     notifyAllPolicyListenersLocked();
                 }
             }
@@ -917,6 +963,14 @@
         });
     }
 
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void addVcnUnderlyingNetworkPolicyListenerForTest(
+            @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+        synchronized (mLock) {
+            addVcnUnderlyingNetworkPolicyListener(listener);
+        }
+    }
+
     /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
     @GuardedBy("mLock")
     @Override
@@ -1000,7 +1054,7 @@
 
             final ParcelUuid subGrp = getSubGroupForNetworkCapabilities(ncCopy);
             boolean isVcnManagedNetwork = false;
-            boolean isRestrictedCarrierWifi = false;
+            boolean isRestricted = false;
             synchronized (mLock) {
                 final Vcn vcn = mVcns.get(subGrp);
                 if (vcn != null) {
@@ -1008,9 +1062,19 @@
                         isVcnManagedNetwork = true;
                     }
 
-                    if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
-                        // Carrier WiFi always restricted if VCN exists (even in safe mode).
-                        isRestrictedCarrierWifi = true;
+                    final Set<Integer> restrictedTransports =
+                            mDeps.getRestrictedTransports(subGrp, mLastSnapshot);
+                    for (int restrictedTransport : restrictedTransports) {
+                        if (ncCopy.hasTransport(restrictedTransport)) {
+                            if (restrictedTransport == TRANSPORT_CELLULAR) {
+                                // Only make a cell network as restricted when the VCN is in
+                                // active mode.
+                                isRestricted |= (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE);
+                            } else {
+                                isRestricted = true;
+                                break;
+                            }
+                        }
                     }
                 }
             }
@@ -1024,14 +1088,16 @@
                 ncBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
             }
 
-            if (isRestrictedCarrierWifi) {
+            if (isRestricted) {
                 ncBuilder.removeCapability(
                         NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
             }
 
             final NetworkCapabilities result = ncBuilder.build();
             final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy(
-                    mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result);
+                    mTrackingNetworkCallback
+                            .requiresRestartForImmutableCapabilityChanges(result),
+                    result);
 
             logVdbg("getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities
                         + "; and lp: " + linkProperties + "; result = " + policy);
@@ -1296,15 +1362,38 @@
             }
         }
 
-        private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) {
-            if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubscriptionIds() == null) {
+        private Set<Integer> getNonTestTransportTypes(NetworkCapabilities caps) {
+            final Set<Integer> transportTypes = new ArraySet<>();
+            for (int t : caps.getTransportTypes()) {
+                transportTypes.add(t);
+            }
+            return transportTypes;
+        }
+
+        private boolean hasSameTransportsAndCapabilities(
+                NetworkCapabilities caps, NetworkCapabilities capsOther) {
+            if (!Objects.equals(
+                    getNonTestTransportTypes(caps), getNonTestTransportTypes(capsOther))) {
+                return false;
+            }
+
+            for (int capability : ALLOWED_CAPABILITIES) {
+                if (caps.hasCapability(capability) != capsOther.hasCapability(capability)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private boolean requiresRestartForImmutableCapabilityChanges(NetworkCapabilities caps) {
+            if (caps.getSubscriptionIds() == null) {
                 return false;
             }
 
             synchronized (mCaps) {
                 for (NetworkCapabilities existing : mCaps.values()) {
-                    if (existing.hasTransport(TRANSPORT_WIFI)
-                            && caps.getSubscriptionIds().equals(existing.getSubscriptionIds())) {
+                    if (caps.getSubscriptionIds().equals(existing.getSubscriptionIds())
+                            && hasSameTransportsAndCapabilities(caps, existing)) {
                         // Restart if any immutable capabilities have changed
                         return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
                                 != caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED);
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 5c305c6..ca4a32f 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -390,8 +390,13 @@
             Objects.requireNonNull(privilegedPackages, "privilegedPackages was null");
             Objects.requireNonNull(subIdToCarrierConfigMap, "subIdToCarrierConfigMap was null");
 
-            mSubIdToInfoMap = Collections.unmodifiableMap(subIdToInfoMap);
-            mSubIdToCarrierConfigMap = Collections.unmodifiableMap(subIdToCarrierConfigMap);
+            mSubIdToInfoMap =
+                    Collections.unmodifiableMap(
+                            new HashMap<Integer, SubscriptionInfo>(subIdToInfoMap));
+            mSubIdToCarrierConfigMap =
+                    Collections.unmodifiableMap(
+                            new HashMap<Integer, PersistableBundleWrapper>(
+                                    subIdToCarrierConfigMap));
 
             final Map<ParcelUuid, Set<String>> unmodifiableInnerSets = new ArrayMap<>();
             for (Entry<ParcelUuid, Set<String>> entry : privilegedPackages.entrySet()) {
diff --git a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
index 999d406..d22ec0a 100644
--- a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
+++ b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
@@ -544,6 +544,20 @@
             return mBundle.getInt(key, defaultValue);
         }
 
+        /**
+         * Returns the value associated with the given key, or null if no mapping of the desired
+         * type exists for the given key or a null value is explicitly associated with the key.
+         *
+         * @param key a String, or null
+         * @param defaultValue the value to return if key does not exist
+         * @return an int[] value, or null
+         */
+        @Nullable
+        public int[] getIntArray(@Nullable String key, @Nullable int[] defaultValue) {
+            final int[] value = mBundle.getIntArray(key);
+            return value == null ? defaultValue : value;
+        }
+
         @Override
         public int hashCode() {
             return getHashCode(mBundle);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 301fca7..93a4ebf 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -132,6 +132,7 @@
         "libschedulerservicehidl",
         "libsensorservice",
         "libsensorservicehidl",
+        "libsensorserviceaidl",
         "libgui",
         "libtimestats_atoms_proto",
         "libusbhost",
@@ -180,6 +181,7 @@
         "android.hidl.token@1.0-utils",
         "android.frameworks.schedulerservice@1.0",
         "android.frameworks.sensorservice@1.0",
+        "android.frameworks.sensorservice-V1-ndk",
         "android.frameworks.stats@1.0",
         "android.frameworks.stats-V1-ndk",
         "android.system.suspend.control-V1-cpp",
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index b171a07..be18f64 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -14,35 +14,31 @@
  * limitations under the License.
  */
 
-#include <dlfcn.h>
-#include <pthread.h>
-
-#include <chrono>
-#include <thread>
-
-#include <jni.h>
-#include <nativehelper/JNIHelp.h>
-
+#include <android-base/properties.h>
 #include <android/binder_manager.h>
 #include <android/binder_stability.h>
 #include <android/hidl/manager/1.2/IServiceManager.h>
 #include <binder/IServiceManager.h>
+#include <bionic/malloc.h>
+#include <bionic/reserved_signals.h>
+#include <dlfcn.h>
 #include <hidl/HidlTransportSupport.h>
 #include <incremental_service.h>
-
+#include <jni.h>
 #include <memtrackproxy/MemtrackProxy.h>
+#include <nativehelper/JNIHelp.h>
+#include <pthread.h>
 #include <schedulerservice/SchedulingPolicyService.h>
+#include <sensorserviceaidl/SensorManagerAidl.h>
 #include <sensorservicehidl/SensorManager.h>
 #include <stats/StatsAidl.h>
 #include <stats/StatsHal.h>
-
-#include <bionic/malloc.h>
-#include <bionic/reserved_signals.h>
-
-#include <android-base/properties.h>
+#include <utils/AndroidThreads.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
-#include <utils/AndroidThreads.h>
+
+#include <chrono>
+#include <thread>
 
 using namespace std::chrono_literals;
 
@@ -57,7 +53,9 @@
     const std::string instance = std::string() + IStats::descriptor + "/default";
     const binder_exception_t err =
             AServiceManager_addService(statsService->asBinder().get(), instance.c_str());
-    LOG_ALWAYS_FATAL_IF(err != EX_NONE, "Cannot register AIDL %s: %d", instance.c_str(), err);
+    if (err != EX_NONE) {
+        ALOGW("Cannot register AIDL %s: %d", instance.c_str(), err);
+    }
 }
 
 static void startStatsHidlService() {
@@ -69,6 +67,42 @@
     ALOGW_IF(err != android::OK, "Cannot register HIDL %s: %d", IStats::descriptor, err);
 }
 
+static void startSensorManagerAidlService(JNIEnv* env) {
+    using ::aidl::android::frameworks::sensorservice::ISensorManager;
+    using ::android::frameworks::sensorservice::implementation::SensorManagerAidl;
+
+    JavaVM* vm;
+    LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");
+
+    std::shared_ptr<SensorManagerAidl> sensorService =
+            ndk::SharedRefBase::make<SensorManagerAidl>(vm);
+    const std::string instance = std::string() + ISensorManager::descriptor + "/default";
+    const binder_exception_t err =
+            AServiceManager_addService(sensorService->asBinder().get(), instance.c_str());
+    LOG_ALWAYS_FATAL_IF(err != EX_NONE, "Cannot register AIDL %s: %d", instance.c_str(), err);
+}
+
+static void startSensorManagerHidlService(JNIEnv* env) {
+    using ::android::frameworks::sensorservice::V1_0::ISensorManager;
+    using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager;
+    using ::android::hardware::configureRpcThreadpool;
+    using ::android::hidl::manager::V1_0::IServiceManager;
+
+    JavaVM* vm;
+    LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");
+
+    android::sp<ISensorManager> sensorService = new SensorManager(vm);
+    if (IServiceManager::Transport::HWBINDER ==
+        android::hardware::defaultServiceManager1_2()->getTransport(ISensorManager::descriptor,
+                                                                    "default")) {
+        android::status_t err = sensorService->registerAsService();
+        LOG_ALWAYS_FATAL_IF(err != android::OK, "Cannot register %s: %d",
+                            ISensorManager::descriptor, err);
+    } else {
+        ALOGW("%s is deprecated. Skipping registration.", ISensorManager::descriptor);
+    }
+}
+
 } // namespace
 
 namespace android {
@@ -78,6 +112,12 @@
     startStatsAidlService();
 }
 
+static void android_server_SystemServer_startISensorManagerService(JNIEnv* env,
+                                                                   jobject /* clazz */) {
+    startSensorManagerHidlService(env);
+    startSensorManagerAidlService(env);
+}
+
 static void android_server_SystemServer_startMemtrackProxyService(JNIEnv* env,
                                                                   jobject /* clazz */) {
     using aidl::android::hardware::memtrack::MemtrackProxy;
@@ -93,35 +133,19 @@
     LOG_ALWAYS_FATAL_IF(err != EX_NONE, "Cannot register %s: %d", memtrackProxyService, err);
 }
 
-static void android_server_SystemServer_startHidlServices(JNIEnv* env, jobject /* clazz */) {
+static void android_server_SystemServer_startHidlServices(JNIEnv* /* env */, jobject /* clazz */) {
     using ::android::frameworks::schedulerservice::V1_0::ISchedulingPolicyService;
     using ::android::frameworks::schedulerservice::V1_0::implementation::SchedulingPolicyService;
-    using ::android::frameworks::sensorservice::V1_0::ISensorManager;
-    using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager;
     using ::android::hardware::configureRpcThreadpool;
     using ::android::hidl::manager::V1_0::IServiceManager;
 
-    status_t err;
-
     configureRpcThreadpool(5, false /* callerWillJoin */);
 
-    JavaVM *vm;
-    LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");
-
-    sp<ISensorManager> sensorService = new SensorManager(vm);
-    if (IServiceManager::Transport::HWBINDER ==
-        hardware::defaultServiceManager1_2()->getTransport(ISensorManager::descriptor, "default")) {
-        err = sensorService->registerAsService();
-        LOG_ALWAYS_FATAL_IF(err != OK, "Cannot register %s: %d", ISensorManager::descriptor, err);
-    } else {
-        ALOGW("%s is deprecated. Skipping registration.", ISensorManager::descriptor);
-    }
-
     sp<ISchedulingPolicyService> schedulingService = new SchedulingPolicyService();
     if (IServiceManager::Transport::HWBINDER ==
         hardware::defaultServiceManager1_2()->getTransport(ISchedulingPolicyService::descriptor,
                                                            "default")) {
-        err = schedulingService->registerAsService("default");
+        status_t err = schedulingService->registerAsService("default");
         LOG_ALWAYS_FATAL_IF(err != OK, "Cannot register %s: %d",
                             ISchedulingPolicyService::descriptor, err);
     } else {
@@ -156,6 +180,8 @@
 static const JNINativeMethod gMethods[] = {
         /* name, signature, funcPtr */
         {"startIStatsService", "()V", (void*)android_server_SystemServer_startIStatsService},
+        {"startISensorManagerService", "()V",
+         (void*)android_server_SystemServer_startISensorManagerService},
         {"startMemtrackProxyService", "()V",
          (void*)android_server_SystemServer_startMemtrackProxyService},
         {"startHidlServices", "()V", (void*)android_server_SystemServer_startHidlServices},
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c2a6944..a953bcb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -466,6 +466,7 @@
     private final long mRuntimeStartUptime;
 
     private static final String START_HIDL_SERVICES = "StartHidlServices";
+    private static final String START_SENSOR_MANAGER_SERVICE = "StartISensorManagerService";
     private static final String START_BLOB_STORE_SERVICE = "startBlobStoreManagerService";
 
     private static final String SYSPROP_START_COUNT = "sys.system_server.start_count";
@@ -484,6 +485,9 @@
     /** Start the IStats services. This is a blocking call and can take time. */
     private static native void startIStatsService();
 
+    /** Start the ISensorManager service. This is a blocking call and can take time. */
+    private static native void startISensorManagerService();
+
     /**
      * Start the memtrack proxy service.
      */
@@ -1597,11 +1601,18 @@
             wm.onInitReady();
             t.traceEnd();
 
-            // Start receiving calls from HIDL services. Start in in a separate thread
+            // Start receiving calls from SensorManager services. Start in a separate thread
             // because it need to connect to SensorManager. This has to start
             // after PHASE_WAIT_FOR_SENSOR_SERVICE is done.
             SystemServerInitThreadPool.submit(() -> {
                 TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
+                traceLog.traceBegin(START_SENSOR_MANAGER_SERVICE);
+                startISensorManagerService();
+                traceLog.traceEnd();
+            }, START_SENSOR_MANAGER_SERVICE);
+
+            SystemServerInitThreadPool.submit(() -> {
+                TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
                 traceLog.traceBegin(START_HIDL_SERVICES);
                 startHidlServices();
                 traceLog.traceEnd();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
index 116d2d5..cc9a917f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
@@ -102,7 +102,8 @@
                 FaceSensorProperties.TYPE_UNKNOWN, supportsFaceDetection, supportsSelfIllumination,
                 resetLockoutRequiresChallenge);
 
-        Face10.sSystemClock = Clock.fixed(Instant.ofEpochMilli(100), ZoneId.of("PST"));
+        Face10.sSystemClock = Clock.fixed(
+                Instant.ofEpochMilli(100), ZoneId.of("America/Los_Angeles"));
         mFace10 = new Face10(mContext, sensorProps, mLockoutResetDispatcher, mHandler, mScheduler,
                 mBiometricContext);
         mBinder = new Binder();
@@ -112,7 +113,7 @@
         waitForIdle();
         Face10.sSystemClock = Clock.fixed(Instant.ofEpochSecond(
                 Face10.sSystemClock.instant().getEpochSecond() + seconds),
-                ZoneId.of("PST"));
+                ZoneId.of("America/Los_Angeles"));
     }
 
     @Test
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index ad06830..258642ac 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -17,10 +17,12 @@
 package com.android.server;
 
 import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -95,6 +97,7 @@
 import com.android.server.vcn.VcnContext;
 import com.android.server.vcn.VcnNetworkProvider;
 import com.android.server.vcn.util.PersistableBundleUtils;
+import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -252,6 +255,10 @@
                 .when(mMockContext)
                 .enforceCallingOrSelfPermission(
                         eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+        doReturn(Collections.singleton(TRANSPORT_WIFI))
+                .when(mMockDeps)
+                .getRestrictedTransports(any(), any());
     }
 
 
@@ -1031,63 +1038,188 @@
                 new LinkProperties());
     }
 
+    private void checkGetRestrictedTransports(
+            ParcelUuid subGrp,
+            TelephonySubscriptionSnapshot lastSnapshot,
+            Set<Integer> expectedTransports) {
+        Set<Integer> result =
+                new VcnManagementService.Dependencies()
+                        .getRestrictedTransports(subGrp, lastSnapshot);
+        assertEquals(expectedTransports, result);
+    }
+
     @Test
-    public void testGetUnderlyingNetworkPolicyCellular() throws Exception {
+    public void testGetRestrictedTransports() {
+        final Set<Integer> restrictedTransports = new ArraySet<>();
+        restrictedTransports.add(TRANSPORT_CELLULAR);
+        restrictedTransports.add(TRANSPORT_WIFI);
+
+        PersistableBundle carrierConfigBundle = new PersistableBundle();
+        carrierConfigBundle.putIntArray(
+                VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+                restrictedTransports.stream().mapToInt(i -> i).toArray());
+        final PersistableBundleWrapper carrierConfig =
+                new PersistableBundleWrapper(carrierConfigBundle);
+
+        final TelephonySubscriptionSnapshot lastSnapshot =
+                mock(TelephonySubscriptionSnapshot.class);
+        doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
+
+        checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+    }
+
+    @Test
+    public void testGetRestrictedTransports_noRestrictPolicyConfigured() {
+        final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
+
+        final PersistableBundleWrapper carrierConfig =
+                new PersistableBundleWrapper(new PersistableBundle());
+        final TelephonySubscriptionSnapshot lastSnapshot =
+                mock(TelephonySubscriptionSnapshot.class);
+        doReturn(carrierConfig).when(lastSnapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
+
+        checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+    }
+
+    @Test
+    public void testGetRestrictedTransports_noCarrierConfig() {
+        final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI);
+
+        final TelephonySubscriptionSnapshot lastSnapshot =
+                mock(TelephonySubscriptionSnapshot.class);
+
+        checkGetRestrictedTransports(TEST_UUID_2, lastSnapshot, restrictedTransports);
+    }
+
+    private void checkGetUnderlyingNetworkPolicy(
+            int transportType,
+            boolean isTransportRestricted,
+            boolean isActive,
+            boolean expectVcnManaged,
+            boolean expectRestricted)
+            throws Exception {
+
+        final Set<Integer> restrictedTransports = new ArraySet();
+        if (isTransportRestricted) {
+            restrictedTransports.add(transportType);
+        }
+        doReturn(restrictedTransports).when(mMockDeps).getRestrictedTransports(any(), any());
+
         final VcnUnderlyingNetworkPolicy policy =
                 startVcnAndGetPolicyForTransport(
-                        TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_CELLULAR);
+                        TEST_SUBSCRIPTION_ID, TEST_UUID_2, isActive, transportType);
+
+        assertFalse(policy.isTeardownRequested());
+        verifyMergedNetworkCapabilities(
+                policy.getMergedNetworkCapabilities(),
+                transportType,
+                expectVcnManaged,
+                expectRestricted);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicy_unrestrictCell() throws Exception {
+        checkGetUnderlyingNetworkPolicy(
+                TRANSPORT_CELLULAR,
+                false /* isTransportRestricted */,
+                true /* isActive */,
+                true /* expectVcnManaged */,
+                false /* expectRestricted */);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicy_unrestrictCellSafeMode() throws Exception {
+        checkGetUnderlyingNetworkPolicy(
+                TRANSPORT_CELLULAR,
+                false /* isTransportRestricted */,
+                false /* isActive */,
+                false /* expectVcnManaged */,
+                false /* expectRestricted */);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicy_restrictCell() throws Exception {
+        checkGetUnderlyingNetworkPolicy(
+                TRANSPORT_CELLULAR,
+                true /* isTransportRestricted */,
+                true /* isActive */,
+                true /* expectVcnManaged */,
+                true /* expectRestricted */);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicy_restrictCellSafeMode() throws Exception {
+        checkGetUnderlyingNetworkPolicy(
+                TRANSPORT_CELLULAR,
+                true /* isTransportRestricted */,
+                false /* isActive */,
+                false /* expectVcnManaged */,
+                false /* expectRestricted */);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicy_unrestrictWifi() throws Exception {
+        checkGetUnderlyingNetworkPolicy(
+                TRANSPORT_WIFI,
+                false /* isTransportRestricted */,
+                true /* isActive */,
+                true /* expectVcnManaged */,
+                false /* expectRestricted */);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicy_unrestrictWifiSafeMode() throws Exception {
+        checkGetUnderlyingNetworkPolicy(
+                TRANSPORT_WIFI,
+                false /* isTransportRestricted */,
+                false /* isActive */,
+                false /* expectVcnManaged */,
+                false /* expectRestricted */);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicy_restrictWifi() throws Exception {
+        checkGetUnderlyingNetworkPolicy(
+                TRANSPORT_WIFI,
+                true /* isTransportRestricted */,
+                true /* isActive */,
+                true /* expectVcnManaged */,
+                true /* expectRestricted */);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicy_restrictWifiSafeMode() throws Exception {
+        checkGetUnderlyingNetworkPolicy(
+                TRANSPORT_WIFI,
+                true /* isTransportRestricted */,
+                false /* isActive */,
+                false /* expectVcnManaged */,
+                true /* expectRestricted */);
+    }
+
+    @Test
+    public void testGetUnderlyingNetworkPolicyCell_restrictWifi() throws Exception {
+        doReturn(Collections.singleton(TRANSPORT_WIFI))
+                .when(mMockDeps)
+                .getRestrictedTransports(any(), any());
+
+        setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isVcnActive */);
+
+        // Get the policy for a cellular network and expect it won't be affected by the wifi
+        // restriction policy
+        final VcnUnderlyingNetworkPolicy policy =
+                mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+                        getNetworkCapabilitiesBuilderForTransport(
+                                        TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
+                                .build(),
+                        new LinkProperties());
 
         assertFalse(policy.isTeardownRequested());
         verifyMergedNetworkCapabilities(
                 policy.getMergedNetworkCapabilities(),
                 TRANSPORT_CELLULAR,
-                true /* isVcnManaged */,
-                false /* isRestricted */);
-    }
-
-    @Test
-    public void testGetUnderlyingNetworkPolicyCellular_safeMode() throws Exception {
-        final VcnUnderlyingNetworkPolicy policy =
-                startVcnAndGetPolicyForTransport(
-                        TEST_SUBSCRIPTION_ID,
-                        TEST_UUID_2,
-                        false /* isActive */,
-                        TRANSPORT_CELLULAR);
-
-        assertFalse(policy.isTeardownRequested());
-        verifyMergedNetworkCapabilities(
-                policy.getMergedNetworkCapabilities(),
-                NetworkCapabilities.TRANSPORT_CELLULAR,
-                false /* isVcnManaged */,
-                false /* isRestricted */);
-    }
-
-    @Test
-    public void testGetUnderlyingNetworkPolicyWifi() throws Exception {
-        final VcnUnderlyingNetworkPolicy policy =
-                startVcnAndGetPolicyForTransport(
-                        TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_WIFI);
-
-        assertFalse(policy.isTeardownRequested());
-        verifyMergedNetworkCapabilities(
-                policy.getMergedNetworkCapabilities(),
-                NetworkCapabilities.TRANSPORT_WIFI,
-                true /* isVcnManaged */,
-                true /* isRestricted */);
-    }
-
-    @Test
-    public void testGetUnderlyingNetworkPolicyVcnWifi_safeMode() throws Exception {
-        final VcnUnderlyingNetworkPolicy policy =
-                startVcnAndGetPolicyForTransport(
-                        TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
-
-        assertFalse(policy.isTeardownRequested());
-        verifyMergedNetworkCapabilities(
-                policy.getMergedNetworkCapabilities(),
-                NetworkCapabilities.TRANSPORT_WIFI,
-                false /* isVcnManaged */,
-                true /* isRestricted */);
+                true /* expectVcnManaged */,
+                false /* expectRestricted */);
     }
 
     private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
@@ -1138,6 +1270,27 @@
     }
 
     @Test
+    public void testGetUnderlyingNetworkPolicyForRestrictedImsWhenUnrestrictingCell()
+            throws Exception {
+        final NetworkCapabilities existingNetworkCaps =
+                getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
+                        .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                        .removeCapability(NET_CAPABILITY_IMS)
+                        .build();
+        setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+        final VcnUnderlyingNetworkPolicy policy =
+                mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+                        getNetworkCapabilitiesBuilderForTransport(
+                                        TEST_SUBSCRIPTION_ID, TRANSPORT_CELLULAR)
+                                .addCapability(NET_CAPABILITY_IMS)
+                                .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                                .build(),
+                        new LinkProperties());
+        assertFalse(policy.isTeardownRequested());
+    }
+
+    @Test
     public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
         setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);
 
@@ -1217,6 +1370,30 @@
         verify(mMockPolicyListener).onPolicyChanged();
     }
 
+    @Test
+    public void testVcnCarrierConfigChangeUpdatesPolicyListener() throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
+        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListenerForTest(mMockPolicyListener);
+
+        final TelephonySubscriptionSnapshot snapshot =
+                buildSubscriptionSnapshot(
+                        TEST_SUBSCRIPTION_ID,
+                        TEST_UUID_2,
+                        Collections.singleton(TEST_UUID_2),
+                        Collections.emptyMap(),
+                        true /* hasCarrierPrivileges */);
+
+        final PersistableBundleWrapper mockCarrierConfig = mock(PersistableBundleWrapper.class);
+        doReturn(mockCarrierConfig).when(snapshot).getCarrierConfigForSubGrp(eq(TEST_UUID_2));
+
+        final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+        cb.onNewSnapshot(snapshot);
+
+        verify(mMockPolicyListener).onPolicyChanged();
+    }
+
     private void triggerVcnSafeMode(
             @NonNull ParcelUuid subGroup,
             @NonNull TelephonySubscriptionSnapshot snapshot,
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 09080be..965b073 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -16,6 +16,9 @@
 
 package com.android.server.vcn;
 
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnManager.VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY;
 import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
 import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
 import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
@@ -39,6 +42,7 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -494,6 +498,37 @@
     }
 
     @Test
+    public void testCarrierConfigUpdatedAfterValidTriggersCallbacks() throws Exception {
+        mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+        mTestLooper.dispatchAll();
+        verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
+        reset(mCallback);
+
+        final PersistableBundle updatedConfig = new PersistableBundle();
+        updatedConfig.putIntArray(
+                VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+                new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR});
+        doReturn(updatedConfig)
+                .when(mCarrierConfigManager)
+                .getConfigForSubId(eq(TEST_SUBSCRIPTION_ID_1));
+
+        Map<Integer, PersistableBundleWrapper> subIdToCarrierConfigMap = new HashMap<>();
+        subIdToCarrierConfigMap.put(
+                TEST_SUBSCRIPTION_ID_1, new PersistableBundleWrapper(updatedConfig));
+        mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+        mTestLooper.dispatchAll();
+
+        verify(mCallback)
+                .onNewSnapshot(
+                        eq(
+                                buildExpectedSnapshot(
+                                        0,
+                                        TEST_SUBID_TO_INFO_MAP,
+                                        subIdToCarrierConfigMap,
+                                        TEST_PRIVILEGED_PACKAGES)));
+    }
+
+    @Test
     public void testSlotClearedAfterValidTriggersCallbacks() throws Exception {
         mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
         mTestLooper.dispatchAll();