Merge "Introduce audio playback capture API"
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d78647e..62926cb 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5630,7 +5630,7 @@
  *   frameworks/base/packages/SystemUI/
  */
 message AssistGestureStageReported {
-  optional android.hardware.sensor.assist.AssistGestureStageEnum gesture_stage = 1;
+    optional android.hardware.sensor.assist.AssistGestureStageEnum gesture_stage = 1;
 }
 
 /**
@@ -5640,8 +5640,8 @@
  *   frameworks/base/packages/SystemUI/
  */
 message AssistGestureFeedbackReported {
-  // Whether or not the gesture was used.
-  optional android.hardware.sensor.assist.AssistGestureFeedbackEnum feedback_type = 1;
+    // Whether or not the gesture was used.
+    optional android.hardware.sensor.assist.AssistGestureFeedbackEnum feedback_type = 1;
 }
 
 /**
@@ -5651,8 +5651,8 @@
  *   frameworks/base/packages/SystemUI/
  */
 message AssistGestureProgressReported {
-  // [0,100] progress for the assist gesture.
-  optional int32 progress = 1;
+    // [0,100] progress for the assist gesture.
+    optional int32 progress = 1;
 }
 
 /*
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 1de8117..de378b0 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -398,8 +398,8 @@
             }
         }
 
-        /**
-         * See com.android.internal.os.SystemZygoteInit.readArgumentList()
+        /*
+         * See com.android.internal.os.ZygoteArguments.parseArgs()
          * Presently the wire format to the zygote process is:
          * a) a count of arguments (argc, in essence)
          * b) a number of newline-separated argument strings equal to count
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 22884ac..0604ab2 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -767,17 +767,6 @@
      * @throws IOException passed straight through
      */
     static String[] readArgumentList(BufferedReader socketReader) throws IOException {
-
-        /**
-         * See android.os.Process.zygoteSendArgsAndGetPid()
-         * Presently the wire format to the zygote process is:
-         * a) a count of arguments (argc, in essence)
-         * b) a number of newline-separated argument strings equal to count
-         *
-         * After the zygote process reads these it will write the pid of
-         * the child or -1 on failure.
-         */
-
         int argc;
 
         try {
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index e6bcd37..c24a9e0 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -217,8 +217,17 @@
      * Per security review bug #1112214, duplicate args are disallowed in critical cases to make
      * injection harder.
      */
-    private void parseArgs(String[] args)
-            throws IllegalArgumentException {
+    private void parseArgs(String[] args) throws IllegalArgumentException {
+        /*
+         * See android.os.ZygoteProcess.zygoteSendArgsAndGetResult()
+         * Presently the wire format to the zygote process is:
+         * a) a count of arguments (argc, in essence)
+         * b) a number of newline-separated argument strings equal to count
+         *
+         * After the zygote process reads these it will write the pid of
+         * the child or -1 on failure.
+         */
+
         int curArg = 0;
 
         boolean seenRuntimeArgs = false;
diff --git a/core/proto/android/hardware/sensor/assist/enums.proto b/core/proto/android/hardware/sensor/assist/enums.proto
index 8c5841a..012dcb2 100644
--- a/core/proto/android/hardware/sensor/assist/enums.proto
+++ b/core/proto/android/hardware/sensor/assist/enums.proto
@@ -21,14 +21,14 @@
 option java_multiple_files = true;
 
 enum AssistGestureStageEnum {
-  ASSIST_GESTURE_STAGE_UNKNOWN = 0;
-  ASSIST_GESTURE_STAGE_PROGRESS = 1;
-  ASSIST_GESTURE_STAGE_PRIMED = 2;
-  ASSIST_GESTURE_STAGE_DETECTED = 3;
+    ASSIST_GESTURE_STAGE_UNKNOWN = 0;
+    ASSIST_GESTURE_STAGE_PROGRESS = 1;
+    ASSIST_GESTURE_STAGE_PRIMED = 2;
+    ASSIST_GESTURE_STAGE_DETECTED = 3;
 }
 
 enum AssistGestureFeedbackEnum {
-  ASSIST_GESTURE_FEEDBACK_UNKNOWN = 0;
-  ASSIST_GESTURE_FEEDBACK_NOT_USED = 1;
-  ASSIST_GESTURE_FEEDBACK_USED = 2;
+    ASSIST_GESTURE_FEEDBACK_UNKNOWN = 0;
+    ASSIST_GESTURE_FEEDBACK_NOT_USED = 1;
+    ASSIST_GESTURE_FEEDBACK_USED = 2;
 }
\ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
index 8077431..efa4387 100644
--- a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
+++ b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
@@ -16,25 +16,21 @@
 
 package com.android.systemui.notifications;
 
+import android.app.ActivityManager;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
-import android.app.ActivityManager;
 import android.car.Car;
 import android.car.CarNotConnectedException;
 import android.car.drivingstate.CarUxRestrictionsManager;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.os.IBinder;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.GestureDetector;
@@ -95,28 +91,12 @@
     private static int sSettleOpenPercentage;
     private static int sSettleClosePercentage;
 
-    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_USER_SWITCHED)) {
-                mCarNotificationListener.registerAsSystemService(mContext,
-                        mCarUxRestrictionManagerWrapper,
-                        mClickHandlerFactory);
-                inflateNotificationContent();
-            }
-        }
-    };
-
     /**
      * Inits the window that hosts the notifications and establishes the connections
      * to the car related services.
      */
     @Override
     public void start() {
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
         sSettleOpenPercentage = mContext.getResources().getInteger(
                 R.integer.notification_settle_open_percentage);
         sSettleClosePercentage = mContext.getResources().getInteger(
@@ -133,11 +113,12 @@
                         ServiceManager.getService(Context.STATUS_BAR_SERVICE)),
                 launchResult -> {
                     if (launchResult == ActivityManager.START_TASK_TO_FRONT
-                            || launchResult == ActivityManager.START_SUCCESS) {
+                            || launchResult == ActivityManager.START_SUCCESS){
                         closeCarNotifications(DEFAULT_FLING_VELOCITY);
                     }
                 });
-
+        mCarNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper,
+                mClickHandlerFactory);
         mCar = Car.createCar(mContext, mCarConnectionListener);
         mCar.connect();
         NotificationGestureListener gestureListener = new NotificationGestureListener();
@@ -150,6 +131,8 @@
         mCarNotificationWindow
                 .setBackgroundColor(mContext.getColor(R.color.notification_shade_background_color));
 
+        inflateNotificationContent();
+
         WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY,
@@ -220,7 +203,7 @@
         // There's a view installed at a higher z-order such that we can intercept the ACTION_DOWN
         // to set the initial click state.
         mCarNotificationWindow.findViewById(R.id.glass_pane).setOnTouchListener((v, event) -> {
-            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+            if (event.getActionMasked() == MotionEvent.ACTION_UP ) {
                 mNotificationListAtBottomAtTimeOfTouch = false;
             }
             if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
@@ -271,7 +254,7 @@
         public boolean onTouch(View v, MotionEvent event) {
             // reset mNotificationListAtBottomAtTimeOfTouch here since the "glass pane" will not
             // get the up event
-            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+            if (event.getActionMasked() == MotionEvent.ACTION_UP ) {
                 mNotificationListAtBottomAtTimeOfTouch = false;
             }
             boolean wasScrolledUp = mScrollUpDetector.onTouchEvent(event);
@@ -355,7 +338,7 @@
         public boolean onFling(MotionEvent event1, MotionEvent event2,
                 float velocityX, float velocityY) {
             if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
-                    || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
+                    || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY){
                 // swipe was not vertical or was not fast enough
                 return false;
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b1c186e..9ff2f44 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -15835,6 +15835,12 @@
 
             if (reconciledPkg.prepareResult.replace) {
                 PackageParser.Package oldPackage = mPackages.get(packageName);
+
+                // Set the update and install times
+                PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
+                setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
+                        System.currentTimeMillis());
+
                 if (reconciledPkg.prepareResult.system) {
                     // Remove existing system package
                     removePackageLI(oldPackage, true);
@@ -15850,11 +15856,6 @@
                         res.removedInfo.args = null;
                     }
 
-                    // Set the update and install times
-                    PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
-                    setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
-                            System.currentTimeMillis());
-
                     // Update the package dynamic state if succeeded
                     // Now that the install succeeded make sure we remove data
                     // directories for any child package the update removed.
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index 8d9b3cf..fe4825c 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -23,12 +23,14 @@
 import static org.testng.Assert.assertEquals;
 
 import android.app.usage.EventList;
+import android.app.usage.TimeSparseArray;
 import android.app.usage.UsageEvents.Event;
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.AtomicFile;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -38,6 +40,7 @@
 import org.junit.runner.RunWith;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.List;
 import java.util.Locale;
@@ -448,4 +451,45 @@
         runBackupRestoreTest(0);
         runBackupRestoreTest(99999);
     }
+
+    /**
+     * Test the pruning in indexFilesLocked() that only allow up to 100 daily files, 50 weekly files
+     * , 12 monthly files, 10 yearly files.
+     */
+    @Test
+    public void testMaxFiles() throws IOException {
+        final File[] intervalDirs = new File[]{
+            new File(mTestDir, "daily"),
+            new File(mTestDir, "weekly"),
+            new File(mTestDir, "monthly"),
+            new File(mTestDir, "yearly"),
+        };
+        // Create 10 extra files under each interval dir.
+        final int extra = 10;
+        final int length = intervalDirs.length;
+        for (int i = 0; i < length; i++) {
+            final int numFiles = UsageStatsDatabase.MAX_FILES_PER_INTERVAL_TYPE[i] + extra;
+            for (int f = 0; f < numFiles; f++) {
+                final AtomicFile file = new AtomicFile(new File(intervalDirs[i], Long.toString(f)));
+                FileOutputStream fos = file.startWrite();
+                fos.write(1);
+                file.finishWrite(fos);
+            }
+        }
+        // indexFilesLocked() list files under each interval dir, if number of files are more than
+        // the max allowed files for each interval type, it deletes the lowest numbered files.
+        mUsageStatsDatabase.forceIndexFiles();
+        final int len = mUsageStatsDatabase.mSortedStatFiles.length;
+        for (int i = 0; i < len; i++) {
+            final TimeSparseArray<AtomicFile> files =  mUsageStatsDatabase.mSortedStatFiles[i];
+            // The stats file for each interval type equals to max allowed.
+            assertEquals(UsageStatsDatabase.MAX_FILES_PER_INTERVAL_TYPE[i],
+                    files.size());
+            // The highest numbered file,
+            assertEquals(UsageStatsDatabase.MAX_FILES_PER_INTERVAL_TYPE[i] + extra - 1,
+                    files.keyAt(files.size() - 1));
+            // The lowest numbered file:
+            assertEquals(extra, files.keyAt(0));
+        }
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 0e15947..dff6809 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -43,8 +43,8 @@
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.FilenameFilter;
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
@@ -84,6 +84,9 @@
     @VisibleForTesting
     public static final int BACKUP_VERSION = 4;
 
+    @VisibleForTesting
+    static final int[] MAX_FILES_PER_INTERVAL_TYPE = new int[]{100, 50, 12, 10};
+
     // Key under which the payload blob is stored
     // same as UsageStatsBackupHelper.KEY_USAGE_STATS
     static final String KEY_USAGE_STATS = "usage_stats";
@@ -104,7 +107,8 @@
 
     private final Object mLock = new Object();
     private final File[] mIntervalDirs;
-    private final TimeSparseArray<AtomicFile>[] mSortedStatFiles;
+    @VisibleForTesting
+    final TimeSparseArray<AtomicFile>[] mSortedStatFiles;
     private final UnixCalendar mCal;
     private final File mVersionFile;
     private final File mBackupsDir;
@@ -126,10 +130,10 @@
     @VisibleForTesting
     public UsageStatsDatabase(File dir, int version) {
         mIntervalDirs = new File[]{
-                new File(dir, "daily"),
-                new File(dir, "weekly"),
-                new File(dir, "monthly"),
-                new File(dir, "yearly"),
+            new File(dir, "daily"),
+            new File(dir, "weekly"),
+            new File(dir, "monthly"),
+            new File(dir, "yearly"),
         };
         mCurrentVersion = version;
         mVersionFile = new File(dir, "version");
@@ -248,6 +252,14 @@
         return true;
     }
 
+    /** @hide */
+    @VisibleForTesting
+    void forceIndexFiles() {
+        synchronized (mLock) {
+            indexFilesLocked();
+        }
+    }
+
     private void indexFilesLocked() {
         final FilenameFilter backupFileFilter = new FilenameFilter() {
             @Override
@@ -255,7 +267,6 @@
                 return !name.endsWith(BAK_SUFFIX);
             }
         };
-
         // Index the available usage stat files on disk.
         for (int i = 0; i < mSortedStatFiles.length; i++) {
             if (mSortedStatFiles[i] == null) {
@@ -268,8 +279,9 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Found " + files.length + " stat files for interval " + i);
                 }
-
-                for (File f : files) {
+                final int len = files.length;
+                for (int j = 0; j < len; j++) {
+                    final File f = files[j];
                     final AtomicFile af = new AtomicFile(f);
                     try {
                         mSortedStatFiles[i].put(parseBeginTime(af), af);
@@ -277,6 +289,16 @@
                         Slog.e(TAG, "failed to index file: " + f, e);
                     }
                 }
+
+                // only keep the max allowed number of files for each interval type.
+                final int toDelete = mSortedStatFiles[i].size() - MAX_FILES_PER_INTERVAL_TYPE[i];
+                if (toDelete > 0) {
+                    for (int j = 0; j < toDelete; j++) {
+                        mSortedStatFiles[i].valueAt(0).delete();
+                        mSortedStatFiles[i].removeAt(0);
+                    }
+                    Slog.d(TAG, "Deleted " + toDelete + " stat files for interval " + i);
+                }
             }
         }
     }
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 3cb2216..ebd8e36 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -595,8 +595,8 @@
     private void loadActiveStats(final long currentTimeMillis) {
         for (int intervalType = 0; intervalType < mCurrentStats.length; intervalType++) {
             final IntervalStats stats = mDatabase.getLatestUsageStats(intervalType);
-            if (stats != null && currentTimeMillis - 500 >= stats.endTime &&
-                    currentTimeMillis < stats.beginTime + INTERVAL_LENGTH[intervalType]) {
+            if (stats != null
+                    && currentTimeMillis < stats.beginTime + INTERVAL_LENGTH[intervalType]) {
                 if (DEBUG) {
                     Slog.d(TAG, mLogPrefix + "Loading existing stats @ " +
                             sDateFormat.format(stats.beginTime) + "(" + stats.beginTime +