Merge "Introduce new App Ops permission for 3rd-party InCallService" into rvc-qpr-dev-plus-aosp
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 640259e..8900dfd 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.app.compat.CompatChanges;
 import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.icu.text.DateFormatSymbols;
@@ -169,7 +169,7 @@
      * mean using 12-hour in some locales and, in this case, is duplicated as the 'a' field.
      */
     @ChangeId
-    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT)
     static final long DISALLOW_DUPLICATE_FIELD_IN_SKELETON = 170233598L;
 
     /**
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index 6fbee16..861a8ef 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -105,7 +105,8 @@
         }
 
         Intent nextActivity = new Intent(intent);
-        nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+        nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+                | Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
         // The the installation source as the nextActivity thinks this activity is the source, hence
         // set the originating UID and sourceInfo explicitly
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 331ba9f..e09a45f9 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -249,6 +249,13 @@
     // 20% as a conservative estimate.
     private static final int MAX_PROCSTATS_RAW_SHARD_SIZE = (int) (MAX_PROCSTATS_SHARD_SIZE * 1.20);
 
+    /**
+     * Threshold to filter out small CPU times at frequency per UID. Those small values appear
+     * because of more precise accounting in a BPF program. Discarding them reduces the data by at
+     * least 20% with negligible error.
+     */
+    private static final int MIN_CPU_TIME_PER_UID_FREQ = 10;
+
     private final Object mThermalLock = new Object();
     @GuardedBy("mThermalLock")
     private IThermalService mThermalService;
@@ -1556,7 +1563,7 @@
     int pullCpuTimePerUidFreqLocked(int atomTag, List<StatsEvent> pulledData) {
         mCpuUidFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> {
             for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) {
-                if (cpuFreqTimeMs[freqIndex] != 0) {
+                if (cpuFreqTimeMs[freqIndex] >= MIN_CPU_TIME_PER_UID_FREQ) {
                     StatsEvent e = StatsEvent.newBuilder()
                             .setAtomId(atomTag)
                             .writeInt(uid)
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 0c5cd7e..86441e7 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -372,6 +372,14 @@
             "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
 
     /**
+     * A string value for {@link #EXTRA_CALL_DISCONNECT_MESSAGE}, indicates the call was dropped by
+     * lower layers
+     * @hide
+     */
+    public static final String CALL_AUTO_DISCONNECT_MESSAGE_STRING =
+            "Call dropped by lower layers";
+
+    /**
      * Optional extra for {@link android.telephony.TelephonyManager#ACTION_PHONE_STATE_CHANGED}
      * containing the component name of the associated connection service.
      * @hide
diff --git a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
index 1733386..1139fd6 100644
--- a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
+++ b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.util.test;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -114,6 +115,24 @@
         return this;
     }
 
+    /** Stages multiple APEXs within the host test jar onto the device. */
+    public SystemPreparer stageMultiplePackages(String[] resourcePaths, String[] packageNames)
+            throws DeviceNotAvailableException, IOException {
+        assertEquals(resourcePaths.length, packageNames.length);
+        final ITestDevice device = mDeviceProvider.getDevice();
+        final String[] adbCommandLine = new String[resourcePaths.length + 2];
+        adbCommandLine[0] = "install-multi-package";
+        adbCommandLine[1] = "--staged";
+        for (int i = 0; i < resourcePaths.length; i++) {
+            final File tmpFile = copyResourceToTemp(resourcePaths[i]);
+            adbCommandLine[i + 2] = tmpFile.getAbsolutePath();
+            mInstalledPackages.add(packageNames[i]);
+        }
+        final String output = device.executeAdbCommand(adbCommandLine);
+        assertTrue(output.contains("Success. Reboot device to apply staged session"));
+        return this;
+    }
+
     /** Sets the enable state of an overlay package. */
     public SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
             throws DeviceNotAvailableException {
@@ -182,9 +201,27 @@
         return this;
     }
 
+    private static @Nullable String getFileExtension(@Nullable String path) {
+        if (path == null) {
+            return null;
+        }
+        final int lastDot = path.lastIndexOf('.');
+        if (lastDot >= 0) {
+            return path.substring(lastDot + 1);
+        } else {
+            return null;
+        }
+    }
+
     /** Copies a file within the host test jar to a temporary file on the host machine. */
     private File copyResourceToTemp(String resourcePath) throws IOException {
-        final File tempFile = mHostTempFolder.newFile();
+        final String ext = getFileExtension(resourcePath);
+        final File tempFile;
+        if (ext != null) {
+            tempFile = File.createTempFile("junit", "." + ext, mHostTempFolder.getRoot());
+        } else {
+            tempFile = mHostTempFolder.newFile();
+        }
         final ClassLoader classLoader = getClass().getClassLoader();
         try (InputStream assetIs = classLoader.getResourceAsStream(resourcePath);
              FileOutputStream assetOs = new FileOutputStream(tempFile)) {