Merge "[automerger skipped] Merge "Import translations. DO NOT MERGE" into cw-f-dev am: d6df52e22f  -s ours skipped: 7f649e7e6d am: 5cd687505a  -s ours am: 77803cc4fa  -s ours am: 4f65db7421  -s ours am: b98b5de9f3  -s ours"
diff --git a/cmds/incident/main.cpp b/cmds/incident/main.cpp
index 519852d..cdec6a0 100644
--- a/cmds/incident/main.cpp
+++ b/cmds/incident/main.cpp
@@ -148,9 +148,19 @@
 static int
 get_dest(const char* arg)
 {
-    if (strcmp(arg, "LOCAL") == 0) return 0;
-    if (strcmp(arg, "EXPLICIT") == 0) return 1;
-    if (strcmp(arg, "AUTOMATIC") == 0) return 2;
+    if (strcmp(arg, "L") == 0
+        || strcmp(arg, "LOCAL") == 0) {
+      return DEST_LOCAL;
+    }
+    if (strcmp(arg, "E") == 0
+        || strcmp(arg, "EXPLICIT") == 0) {
+      return DEST_EXPLICIT;
+    }
+    if (strcmp(arg, "A") == 0
+        || strcmp(arg, "AUTO") == 0
+        || strcmp(arg, "AUTOMATIC") == 0) {
+      return DEST_AUTOMATIC;
+    }
     return -1; // return the default value
 }
 
diff --git a/cmds/incidentd/src/Privacy.cpp b/cmds/incidentd/src/Privacy.cpp
index 5db2239..44adaec 100644
--- a/cmds/incidentd/src/Privacy.cpp
+++ b/cmds/incidentd/src/Privacy.cpp
@@ -67,8 +67,14 @@
 
 PrivacySpec new_spec_from_args(int dest)
 {
-  if (dest < 0) return PrivacySpec();
-  return PrivacySpec(dest);
+    switch (dest) {
+        case android::os::DEST_AUTOMATIC:
+        case android::os::DEST_EXPLICIT:
+        case android::os::DEST_LOCAL:
+            return PrivacySpec(dest);
+        default:
+            return PrivacySpec();
+    }
 }
 
 PrivacySpec get_default_dropbox_spec() { return PrivacySpec(android::os::DEST_AUTOMATIC); }
\ No newline at end of file
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 998ac5f..c34f4d9 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.app.ActivityThread.ActivityClientRecord;
+import android.app.servertransaction.PendingTransactionActions;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.os.Binder;
@@ -141,6 +143,21 @@
             }
             r.window = r.activity.getWindow();
             r.instanceState = null;
+
+            final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r);
+            final PendingTransactionActions pendingActions;
+
+            if (!r.activity.mFinished) {
+                // This matches pending actions set in ActivityThread#handleLaunchActivity
+                pendingActions = new PendingTransactionActions();
+                pendingActions.setOldState(clientRecord.state);
+                pendingActions.setRestoreInstanceState(true);
+                pendingActions.setCallOnPostCreate(true);
+            } else {
+                pendingActions = null;
+            }
+
+            mActivityThread.handleStartActivity(clientRecord, pendingActions);
             r.curState = STARTED;
             
             if (desiredState == RESUMED) {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 746a090..f6697e8 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -602,6 +602,13 @@
      */
     public static final int PRIVATE_FLAG_VENDOR = 1 << 18;
 
+    /**
+     * Value for {@linl #privateFlags}: whether this app is pre-installed on the
+     * product partition of the system image.
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_PRODUCT = 1 << 19;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
             PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -619,6 +626,7 @@
             PRIVATE_FLAG_OEM,
             PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE,
             PRIVATE_FLAG_PRIVILEGED,
+            PRIVATE_FLAG_PRODUCT,
             PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER,
             PRIVATE_FLAG_STATIC_SHARED_LIBRARY,
             PRIVATE_FLAG_VENDOR,
@@ -1699,6 +1707,11 @@
         return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
     }
 
+    /** @hide */
+    public boolean isProduct() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+    }
+
     /**
      * Returns whether or not this application was installed as a virtual preload.
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 3bb812b..d5c88aa 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6393,6 +6393,11 @@
         }
 
         /** @hide */
+        public boolean isProduct() {
+            return applicationInfo.isProduct();
+        }
+
+        /** @hide */
         public boolean isPrivileged() {
             return applicationInfo.isPrivilegedApp();
         }
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 158041d..03203d0 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -41,6 +41,7 @@
     private static final String ENV_OEM_ROOT = "OEM_ROOT";
     private static final String ENV_ODM_ROOT = "ODM_ROOT";
     private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
+    private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT";
 
     /** {@hide} */
     public static final String DIR_ANDROID = "Android";
@@ -62,6 +63,7 @@
     private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
     private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm");
     private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
+    private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product");
 
     private static UserEnvironment sCurrentUser;
     private static boolean sUserRequired;
@@ -180,6 +182,16 @@
     }
 
     /**
+     * Return root directory of the "product" partition holding product-specific
+     * customizations if any. If present, the partition is mounted read-only.
+     *
+     * @hide
+     */
+    public static File getProductDirectory() {
+        return DIR_PRODUCT_ROOT;
+    }
+
+    /**
      * Return the system directory for a user. This is for use by system
      * services to store files relating to the user. This directory will be
      * automatically deleted when the user is removed.
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index c5af897..111934f 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -149,6 +149,9 @@
     final ArrayMap<String, ArraySet<String>> mVendorPrivAppPermissions = new ArrayMap<>();
     final ArrayMap<String, ArraySet<String>> mVendorPrivAppDenyPermissions = new ArrayMap<>();
 
+    final ArrayMap<String, ArraySet<String>> mProductPrivAppPermissions = new ArrayMap<>();
+    final ArrayMap<String, ArraySet<String>> mProductPrivAppDenyPermissions = new ArrayMap<>();
+
     final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
 
     public static SystemConfig getInstance() {
@@ -240,6 +243,14 @@
         return mVendorPrivAppDenyPermissions.get(packageName);
     }
 
+    public ArraySet<String> getProductPrivAppPermissions(String packageName) {
+        return mProductPrivAppPermissions.get(packageName);
+    }
+
+    public ArraySet<String> getProductPrivAppDenyPermissions(String packageName) {
+        return mProductPrivAppDenyPermissions.get(packageName);
+    }
+
     public Map<String, Boolean> getOemPermissions(String packageName) {
         final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName);
         if (oemPermissions != null) {
@@ -278,6 +289,14 @@
                 Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
         readPermissions(Environment.buildPath(
                 Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
+
+        // Allow Product to customize system configs around libs, features, permissions and apps
+        int productPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
+                ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
+        readPermissions(Environment.buildPath(
+                Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag);
+        readPermissions(Environment.buildPath(
+                Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag);
     }
 
     void readPermissions(File libraryDir, int permissionFlag) {
@@ -598,15 +617,20 @@
                     }
                     XmlUtils.skipCurrentTag(parser);
                 } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
-                    // privapp permissions from system and vendor partitions are stored
+                    // privapp permissions from system, vendor and product partitions are stored
                     // separately. This is to prevent xml files in the vendor partition from
                     // granting permissions to priv apps in the system partition and vice
                     // versa.
                     boolean vendor = permFile.toPath().startsWith(
                             Environment.getVendorDirectory().toPath());
+                    boolean product = permFile.toPath().startsWith(
+                            Environment.getProductDirectory().toPath());
                     if (vendor) {
                         readPrivAppPermissions(parser, mVendorPrivAppPermissions,
                                 mVendorPrivAppDenyPermissions);
+                    } else if (product) {
+                        readPrivAppPermissions(parser, mProductPrivAppPermissions,
+                                mProductPrivAppDenyPermissions);
                     } else {
                         readPrivAppPermissions(parser, mPrivAppPermissions,
                                 mPrivAppDenyPermissions);
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 403937b..7e17a49 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -174,6 +174,10 @@
           argv[argc++] = AssetManager::OVERLAY_DIR;
       }
 
+      if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
+          argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
+      }
+
       // Finally, invoke idmap (if any overlay directory exists)
       if (argc > 5) {
         execv(AssetManager::IDMAP_BIN, (char* const*)argv);
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 956b724..3b7b14c 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -85,11 +85,15 @@
   static const char* kOverlayDir = "/system/vendor/overlay/";
   static const char* kVendorOverlayDir = "/vendor/overlay";
   static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/";
+  static const char* kSystemProductOverlayDir = "/system/product/overlay/";
+  static const char* kProductOverlayDir = "/product/overlay";
   static const char* kApkSuffix = ".apk";
 
   if ((android::base::StartsWith(path, kOverlayDir)
        || android::base::StartsWith(path, kOverlaySubdir)
-       || android::base::StartsWith(path, kVendorOverlayDir))
+       || android::base::StartsWith(path, kVendorOverlayDir)
+       || android::base::StartsWith(path, kSystemProductOverlayDir)
+       || android::base::StartsWith(path, kProductOverlayDir))
       && android::base::EndsWith(path, kApkSuffix)
       && path.find("/../") == std::string::npos) {
     return true;
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 0485625..a5698af 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -73,6 +73,7 @@
 const char* AssetManager::RESOURCES_FILENAME = "resources.arsc";
 const char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
 const char* AssetManager::OVERLAY_DIR = "/vendor/overlay";
+const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay";
 const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme";
 const char* AssetManager::TARGET_PACKAGE_NAME = "android";
 const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h
index ecc5dc1..08da731 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -60,6 +60,7 @@
     static const char* RESOURCES_FILENAME;
     static const char* IDMAP_BIN;
     static const char* OVERLAY_DIR;
+    static const char* PRODUCT_OVERLAY_DIR;
     /*
      * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay
      * APKs in OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index 983ca75..dcd4dce 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -47,11 +47,16 @@
     private SoundPool mSoundPool;
     private SoundState[] mSounds;
 
+    private static final String[] SOUND_DIRS = {
+        "/product/media/audio/ui/",
+        "/system/media/audio/ui/",
+    };
+
     private static final String[] SOUND_FILES = {
-        "/system/media/audio/ui/camera_click.ogg",
-        "/system/media/audio/ui/camera_focus.ogg",
-        "/system/media/audio/ui/VideoRecord.ogg",
-        "/system/media/audio/ui/VideoStop.ogg"
+        "camera_click.ogg",
+        "camera_focus.ogg",
+        "VideoRecord.ogg",
+        "VideoStop.ogg"
     };
 
     private static final String TAG = "MediaActionSound";
@@ -132,12 +137,16 @@
     }
 
     private int loadSound(SoundState sound) {
-        int id = mSoundPool.load(SOUND_FILES[sound.name], 1);
-        if (id > 0) {
-            sound.state = STATE_LOADING;
-            sound.id = id;
+        final String soundFileName = SOUND_FILES[sound.name];
+        for (String soundDir : SOUND_DIRS) {
+            int id = mSoundPool.load(soundDir + soundFileName, 1);
+            if (id > 0) {
+                sound.state = STATE_LOADING;
+                sound.id = id;
+                return id;
+            }
         }
-        return id;
+        return 0;
     }
 
     /**
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index cb4e46f..c309038 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -158,6 +158,7 @@
     public static final String SCANNED_BUILD_PREFS_NAME = "MediaScanBuild";
     public static final String LAST_INTERNAL_SCAN_FINGERPRINT = "lastScanFingerprint";
     private static final String SYSTEM_SOUNDS_DIR = "/system/media/audio";
+    private static final String PRODUCT_SOUNDS_DIR = "/product/media/audio";
     private static String sLastInternalScanFingerprint;
 
     private static final String[] ID3_GENRES = {
@@ -1153,7 +1154,10 @@
     private static boolean isSystemSoundWithMetadata(String path) {
         if (path.startsWith(SYSTEM_SOUNDS_DIR + ALARMS_DIR)
                 || path.startsWith(SYSTEM_SOUNDS_DIR + RINGTONES_DIR)
-                || path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR)) {
+                || path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR)
+                || path.startsWith(PRODUCT_SOUNDS_DIR + ALARMS_DIR)
+                || path.startsWith(PRODUCT_SOUNDS_DIR + RINGTONES_DIR)
+                || path.startsWith(PRODUCT_SOUNDS_DIR + NOTIFICATIONS_DIR)) {
             return true;
         }
         return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 1056ecc..b3f68d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1472,7 +1472,6 @@
         return mPrivateLayout.getActiveRemoteInputText();
     }
 
-
     public void animateTranslateNotification(final float leftTarget) {
         if (mTranslateAnim != null) {
             mTranslateAnim.cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 8336d29..907af69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
+import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.graphics.Matrix;
 import android.graphics.Rect;
@@ -35,10 +36,11 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationListContainer;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarWindowView;
-import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.util.function.Consumer;
 
@@ -57,16 +59,17 @@
     private final NotificationPanelView mNotificationPanel;
     private final NotificationListContainer mNotificationContainer;
     private final StatusBarWindowView mStatusBarWindow;
-    private final Consumer<Boolean> mPanelCollapser;
+    private final StatusBar mStatusBar;
+    private boolean mAnimationPending;
 
     public ActivityLaunchAnimator(StatusBarWindowView statusBarWindow,
-            Consumer<Boolean> panelCollapser,
+            StatusBar statusBar,
             NotificationPanelView notificationPanel,
             NotificationListContainer container) {
         mNotificationPanel = notificationPanel;
         mNotificationContainer = container;
         mStatusBarWindow = statusBarWindow;
-        mPanelCollapser = panelCollapser;
+        mStatusBar = statusBar;
     }
 
     public ActivityOptions getLaunchAnimation(
@@ -76,6 +79,21 @@
                 new RemoteAnimationAdapter(animationRunner, 1000 /* Duration */, 0 /* delay */));
     }
 
+    public boolean isAnimationPending() {
+        return mAnimationPending;
+    }
+
+    public void setLaunchResult(int launchResult) {
+        setAnimationPending((launchResult == ActivityManager.START_TASK_TO_FRONT
+                || launchResult == ActivityManager.START_SUCCESS)
+                        && mStatusBar.getBarState() == StatusBarState.SHADE);
+    }
+
+    private void setAnimationPending(boolean pending) {
+        mAnimationPending = pending;
+        mStatusBarWindow.setExpandAnimationPending(pending);
+    }
+
     class AnimationRunner extends IRemoteAnimationRunner.Stub {
 
         private final ExpandableNotificationRow mSourceNotification;
@@ -94,7 +112,6 @@
                 IRemoteAnimationFinishedCallback iRemoteAnimationFinishedCallback)
                     throws RemoteException {
             mSourceNotification.post(() -> {
-                boolean first = true;
                 for (RemoteAnimationTarget app : remoteAnimationTargets) {
                     if (app.mode == RemoteAnimationTarget.MODE_OPENING) {
                         setExpandAnimationRunning(true);
@@ -139,7 +156,7 @@
                             public void onAnimationEnd(Animator animation) {
                                 setExpandAnimationRunning(false);
                                 if (mInstantCollapsePanel) {
-                                    mPanelCollapser.accept(false /* animate */);
+                                    mStatusBar.collapsePanel(false /* animate */);
                                 }
                                 try {
                                     iRemoteAnimationFinishedCallback.onAnimationFinished();
@@ -152,6 +169,7 @@
                         break;
                     }
                 }
+                setAnimationPending(false);
             });
         }
 
@@ -198,6 +216,10 @@
 
         @Override
         public void onAnimationCancelled() throws RemoteException {
+            mSourceNotification.post(() -> {
+                setAnimationPending(false);
+                mStatusBar.onLaunchAnimationCancelled();
+            });
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index a62a424..2b7e474 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -950,7 +950,7 @@
     }
 
     public boolean isCollapsing() {
-        return mClosing;
+        return mClosing || mLaunchingNotification;
     }
 
     public boolean isTracking() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 7d84550..b519824 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -100,7 +100,6 @@
 import android.service.notification.StatusBarNotification;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
-import android.text.SpannedString;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -589,7 +588,7 @@
 
     private NavigationBarFragment mNavigationBar;
     private View mNavigationBarView;
-    private ActivityLaunchAnimator mActivityLaunchAnimator;
+    protected ActivityLaunchAnimator mActivityLaunchAnimator;
 
     @Override
     public void start() {
@@ -760,7 +759,7 @@
         mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
         mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
         mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow,
-                this::collapsePanel,
+                this,
                 mNotificationPanel,
                 mStackScroller);
         mGutsManager.setUpWithPresenter(this, mEntryManager, mStackScroller, mCheckSaveListener,
@@ -2054,6 +2053,12 @@
         }
     }
 
+    public void onLaunchAnimationCancelled() {
+        if (!isCollapsing()) {
+            onClosingFinished();
+        }
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -3418,7 +3423,7 @@
     }
 
     public boolean isCollapsing() {
-        return mNotificationPanel.isCollapsing();
+        return mNotificationPanel.isCollapsing() || mActivityLaunchAnimator.isAnimationPending();
     }
 
     public void addPostCollapseAction(Runnable r) {
@@ -4959,6 +4964,7 @@
                     try {
                         launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
                                 null, null, getActivityOptions(row));
+                        mActivityLaunchAnimator.setLaunchResult(launchResult);
                     } catch (PendingIntent.CanceledException e) {
                         // the stack trace isn't very helpful here.
                         // Just log the exception message.
@@ -4970,7 +4976,7 @@
                         mAssistManager.hideAssist();
                     }
                 }
-                if (shouldCollapse(launchResult)) {
+                if (shouldCollapse()) {
                     if (Looper.getMainLooper().isCurrentThread()) {
                         collapsePanel();
                     } else {
@@ -5003,17 +5009,8 @@
         }, afterKeyguardGone);
     }
 
-    private boolean shouldCollapse(int launchResult) {
-        return mState != StatusBarState.SHADE
-                || (launchResult != ActivityManager.START_TASK_TO_FRONT
-                        && launchResult != ActivityManager.START_SUCCESS);
-    }
-
-    public void onExpandAnimationFinished() {
-        if (!isPresenterFullyCollapsed()) {
-            instantCollapseNotificationPanel();
-            visibilityChanged(false);
-        }
+    private boolean shouldCollapse() {
+        return mState != StatusBarState.SHADE || !mActivityLaunchAnimator.isAnimationPending();
     }
 
     public void collapsePanel(boolean animate) {
@@ -5128,7 +5125,8 @@
                         .addNextIntentWithParentStack(intent)
                         .startActivities(getActivityOptions(row),
                                 new UserHandle(UserHandle.getUserId(appUid)));
-                if (shouldCollapse(launchResult)) {
+                mActivityLaunchAnimator.setLaunchResult(launchResult);
+                if (shouldCollapse()) {
                     // Putting it back on the main thread, since we're touching views
                     mStatusBarWindow.post(() -> animateCollapsePanels(
                             CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index f7d0967..e32914f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -89,6 +89,7 @@
     private boolean mTouchCancelled;
     private boolean mTouchActive;
     private boolean mExpandAnimationRunning;
+    private boolean mExpandAnimationPending;
 
     public StatusBarWindowView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -268,7 +269,7 @@
                 || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
             setTouchActive(false);
         }
-        if (mTouchCancelled || mExpandAnimationRunning) {
+        if (mTouchCancelled || mExpandAnimationRunning || mExpandAnimationPending) {
             return false;
         }
         mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
@@ -393,6 +394,10 @@
         mExpandAnimationRunning = expandAnimationRunning;
     }
 
+    public void setExpandAnimationPending(boolean pending) {
+        mExpandAnimationPending = pending;
+    }
+
     public class LayoutParams extends FrameLayout.LayoutParams {
 
         public boolean ignoreRightInset;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 1e894ff..3febdfd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -119,7 +119,8 @@
         // for the current foreground user.
         LocationManager locationManager =
                 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
-        return locationManager.isLocationEnabledForUser(Process.myUserHandle());
+        return locationManager.isLocationEnabledForUser(
+                UserHandle.of(ActivityManager.getCurrentUser()));
     }
 
     @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 99202f4..bdf9b1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -84,6 +84,7 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -188,7 +189,8 @@
                 mKeyguardIndicationController, mStackScroller, mHeadsUpManager,
                 mPowerManager, mNotificationPanelView, mBarService, mNotificationListener,
                 mNotificationLogger, mVisualStabilityManager, mViewHierarchyManager,
-                mEntryManager, mScrimController, mFingerprintUnlockController);
+                mEntryManager, mScrimController, mFingerprintUnlockController,
+                mock(ActivityLaunchAnimator.class));
         mStatusBar.mContext = mContext;
         mStatusBar.mComponents = mContext.getComponents();
         mEntryManager.setUpForTest(mStatusBar, mStackScroller, mStatusBar, mHeadsUpManager,
@@ -593,7 +595,8 @@
                 VisualStabilityManager visualStabilityManager,
                 NotificationViewHierarchyManager viewHierarchyManager,
                 TestableNotificationEntryManager entryManager, ScrimController scrimController,
-                FingerprintUnlockController fingerprintUnlockController) {
+                FingerprintUnlockController fingerprintUnlockController,
+                ActivityLaunchAnimator launchAnimator) {
             mStatusBarKeyguardViewManager = man;
             mUnlockMethodCache = unlock;
             mKeyguardIndicationController = key;
@@ -610,6 +613,7 @@
             mEntryManager = entryManager;
             mScrimController = scrimController;
             mFingerprintUnlockController = fingerprintUnlockController;
+            mActivityLaunchAnimator = launchAnimator;
         }
 
         private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index bd93b179..1dd92f3 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1577,13 +1577,22 @@
     }
 
     /**
-     * Returns all providers by name, including passive, but excluding
-     * fused, also including ones that are not permitted to
-     * be accessed by the calling activity or are currently disabled.
+     * Returns all providers by name, including passive and the ones that are not permitted to
+     * be accessed by the calling activity or are currently disabled, but excluding fused.
      */
     @Override
     public List<String> getAllProviders() {
-        List<String> out = getProviders(null /*criteria*/, false /*enabledOnly*/);
+        ArrayList<String> out;
+        synchronized (mLock) {
+            out = new ArrayList<>(mProviders.size());
+            for (LocationProviderInterface provider : mProviders) {
+                String name = provider.getName();
+                if (LocationManager.FUSED_PROVIDER.equals(name)) {
+                    continue;
+                }
+                out.add(name);
+            }
+        }
         if (D) Log.d(TAG, "getAllProviders()=" + out);
         return out;
     }
@@ -2586,9 +2595,10 @@
         // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
         checkInteractAcrossUsersPermission(userId);
 
-        // Enable or disable all location providers
+        // Enable or disable all location providers. Fused provider and passive provider are
+        // excluded.
         synchronized (mLock) {
-            for(String provider : getAllProviders()) {
+            for(String provider : getAllProvidersForLocationSettings()) {
                 setProviderEnabledForUser(provider, enabled, userId);
             }
         }
@@ -2605,9 +2615,10 @@
         // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
         checkInteractAcrossUsersPermission(userId);
 
-        // If at least one location provider is enabled, return true
+        // If at least one location provider is enabled, return true. Fused provider and passive
+        // provider are excluded.
         synchronized (mLock) {
-            for (String provider : getAllProviders()) {
+            for (String provider : getAllProvidersForLocationSettings()) {
                 if (isProviderEnabledForUser(provider, userId)) {
                     return true;
                 }
@@ -2691,6 +2702,26 @@
     }
 
     /**
+     * Return all location providers except fused provider and passive provider. These two
+     * providers are not generating location by themselves, but only echo locations from other
+     * providers.
+     *
+     * @return All location providers except fused provider and passive provider, including
+     *          providers that are not permitted to be accessed by the calling activity or are
+     *          currently disabled.
+     */
+    private List<String> getAllProvidersForLocationSettings() {
+        List<String> providersForSettings = new ArrayList<>(mProviders.size());
+        for (String provider : getAllProviders()) {
+            if (provider.equals(LocationManager.PASSIVE_PROVIDER)) {
+                continue;
+            }
+            providersForSettings.add(provider);
+        }
+        return providersForSettings;
+    }
+
+    /**
      * Read location provider status from Settings.Secure
      *
      * @param provider the location provider to query
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index bedf0431..edeee3e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -133,6 +133,7 @@
 
 import org.xmlpull.v1.XmlPullParserException;
 
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -4767,6 +4768,16 @@
             Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
         }
 
+        private String getSoundEffectFilePath(int effectType) {
+            String filePath = Environment.getProductDirectory() + SOUND_EFFECTS_PATH
+                    + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
+            if (!new File(filePath).isFile()) {
+                filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH
+                        + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
+            }
+            return filePath;
+        }
+
         private boolean onLoadSoundEffects() {
             int status;
 
@@ -4836,9 +4847,7 @@
                         continue;
                     }
                     if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
-                        String filePath = Environment.getRootDirectory()
-                                + SOUND_EFFECTS_PATH
-                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
+                        String filePath = getSoundEffectFilePath(effect);
                         int sampleId = mSoundPool.load(filePath, 0);
                         if (sampleId <= 0) {
                             Log.w(TAG, "Soundpool could not load file: "+filePath);
@@ -4944,8 +4953,7 @@
                 } else {
                     MediaPlayer mediaPlayer = new MediaPlayer();
                     try {
-                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
-                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
+                        String filePath = getSoundEffectFilePath(effectType);
                         mediaPlayer.setDataSource(filePath);
                         mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
                         mediaPlayer.prepare();
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 5bf38dc..10e05cf 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -362,9 +362,10 @@
                 continue;
             }
 
-            // If the path is in /system or /vendor, ignore. It will have been ota-dexopted into
-            // /data/ota and moved into the dalvik-cache already.
-            if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")) {
+            // If the path is in /system, /vendor or /product, ignore. It will have been
+            // ota-dexopted into /data/ota and moved into the dalvik-cache already.
+            if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")
+                    || pkg.codePath.startsWith("/product")) {
                 continue;
             }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 837a118..7767945 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -466,6 +466,7 @@
     static final int SCAN_AS_PRIVILEGED = 1<<18;
     static final int SCAN_AS_OEM = 1<<19;
     static final int SCAN_AS_VENDOR = 1<<20;
+    static final int SCAN_AS_PRODUCT = 1<<21;
 
     @IntDef(flag = true, prefix = { "SCAN_" }, value = {
             SCAN_NO_DEX,
@@ -570,6 +571,8 @@
 
     private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
 
+    private static final String PRODUCT_OVERLAY_DIR = "/product/overlay";
+
     private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob";
 
     /** Canonical intent used to identify what counts as a "web browser" app */
@@ -2552,7 +2555,7 @@
                 scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
             }
 
-            // Collect vendor overlay packages. (Do this before scanning any apps.)
+            // Collect vendor/product overlay packages. (Do this before scanning any apps.)
             // For security and version matching reason, only consider
             // overlay packages if they reside in the right directory.
             scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
@@ -2562,6 +2565,13 @@
                     | SCAN_AS_SYSTEM
                     | SCAN_AS_VENDOR,
                     0);
+            scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR),
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_PRODUCT,
+                    0);
 
             mParallelPackageParserCallback.findStaticOverlayPackages();
 
@@ -2595,8 +2605,7 @@
                     0);
 
             // Collected privileged vendor packages.
-                File privilegedVendorAppDir = new File(Environment.getVendorDirectory(),
-                        "priv-app");
+            File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
             try {
                 privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile();
             } catch (IOException e) {
@@ -2636,6 +2645,37 @@
                     | SCAN_AS_OEM,
                     0);
 
+            // Collected privileged product packages.
+            File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
+            try {
+                privilegedProductAppDir = privilegedProductAppDir.getCanonicalFile();
+            } catch (IOException e) {
+                // failed to look up canonical path, continue with original one
+            }
+            scanDirTracedLI(privilegedProductAppDir,
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_PRODUCT
+                    | SCAN_AS_PRIVILEGED,
+                    0);
+
+            // Collect ordinary product packages.
+            File productAppDir = new File(Environment.getProductDirectory(), "app");
+            try {
+                productAppDir = productAppDir.getCanonicalFile();
+            } catch (IOException e) {
+                // failed to look up canonical path, continue with original one
+            }
+            scanDirTracedLI(productAppDir,
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_PRODUCT,
+                    0);
+
             // Prune any system packages that no longer exist.
             final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
             // Stub packages must either be replaced with full versions in the /data
@@ -2842,6 +2882,23 @@
                                     scanFlags
                                     | SCAN_AS_SYSTEM
                                     | SCAN_AS_OEM;
+                        } else if (FileUtils.contains(privilegedProductAppDir, scanFile)) {
+                            reparseFlags =
+                                    mDefParseFlags |
+                                    PackageParser.PARSE_IS_SYSTEM_DIR;
+                            rescanFlags =
+                                    scanFlags
+                                    | SCAN_AS_SYSTEM
+                                    | SCAN_AS_PRODUCT
+                                    | SCAN_AS_PRIVILEGED;
+                        } else if (FileUtils.contains(productAppDir, scanFile)) {
+                            reparseFlags =
+                                    mDefParseFlags |
+                                    PackageParser.PARSE_IS_SYSTEM_DIR;
+                            rescanFlags =
+                                    scanFlags
+                                    | SCAN_AS_SYSTEM
+                                    | SCAN_AS_PRODUCT;
                         } else {
                             Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                             continue;
@@ -9862,6 +9919,7 @@
      * <li>{@link #SCAN_AS_PRIVILEGED}</li>
      * <li>{@link #SCAN_AS_OEM}</li>
      * <li>{@link #SCAN_AS_VENDOR}</li>
+     * <li>{@link #SCAN_AS_PRODUCT}</li>
      * <li>{@link #SCAN_AS_INSTANT_APP}</li>
      * <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li>
      * </ul>
@@ -9884,6 +9942,10 @@
                     & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) {
                 scanFlags |= SCAN_AS_VENDOR;
             }
+            if ((disabledPkgSetting.pkgPrivateFlags
+                    & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0) {
+                scanFlags |= SCAN_AS_PRODUCT;
+            }
         }
         if (pkgSetting != null) {
             final int userId = ((user == null) ? 0 : user.getIdentifier());
@@ -10662,6 +10724,10 @@
             pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
         }
 
+        if ((scanFlags & SCAN_AS_PRODUCT) != 0) {
+            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT;
+        }
+
         if (!isSystemApp(pkg)) {
             // Only system apps can use these features.
             pkg.mOriginalPackages = null;
@@ -11708,6 +11774,8 @@
             codeRoot = Environment.getOemDirectory();
         } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
             codeRoot = Environment.getVendorDirectory();
+        } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
+            codeRoot = Environment.getProductDirectory();
         } else {
             // Unrecognized code path; take its top real segment as the apk root:
             // e.g. /something/app/blah.apk => /something
@@ -16110,7 +16178,7 @@
 
         boolean sysPkg = (isSystemApp(oldPackage));
         if (sysPkg) {
-            // Set the system/privileged/oem/vendor flags as needed
+            // Set the system/privileged/oem/vendor/product flags as needed
             final boolean privileged =
                     (oldPackage.applicationInfo.privateFlags
                             & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
@@ -16120,12 +16188,16 @@
             final boolean vendor =
                     (oldPackage.applicationInfo.privateFlags
                             & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+            final boolean product =
+                    (oldPackage.applicationInfo.privateFlags
+                            & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
             final @ParseFlags int systemParseFlags = parseFlags;
             final @ScanFlags int systemScanFlags = scanFlags
                     | SCAN_AS_SYSTEM
                     | (privileged ? SCAN_AS_PRIVILEGED : 0)
                     | (oem ? SCAN_AS_OEM : 0)
-                    | (vendor ? SCAN_AS_VENDOR : 0);
+                    | (vendor ? SCAN_AS_VENDOR : 0)
+                    | (product ? SCAN_AS_PRODUCT : 0);
 
             replaceSystemPackageLIF(oldPackage, pkg, systemParseFlags, systemScanFlags,
                     user, allUsers, installerPackageName, res, installReason);
@@ -17373,6 +17445,10 @@
         return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
     }
 
+    private static boolean isProductApp(PackageParser.Package pkg) {
+        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+    }
+
     private static boolean hasDomainURLs(PackageParser.Package pkg) {
         return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
     }
@@ -18112,8 +18188,10 @@
         try {
             final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
             final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
+            final File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
             return path.startsWith(privilegedAppDir.getCanonicalPath())
-                    || path.startsWith(privilegedVendorAppDir.getCanonicalPath());
+                    || path.startsWith(privilegedVendorAppDir.getCanonicalPath())
+                    || path.startsWith(privilegedProductAppDir.getCanonicalPath());
         } catch (IOException e) {
             Slog.e(TAG, "Unable to access code path " + path);
         }
@@ -18138,6 +18216,15 @@
         return false;
     }
 
+    static boolean locationIsProduct(String path) {
+        try {
+            return path.startsWith(Environment.getProductDirectory().getCanonicalPath());
+        } catch (IOException e) {
+            Slog.e(TAG, "Unable to access code path " + path);
+        }
+        return false;
+    }
+
     /*
      * Tries to delete system package.
      */
@@ -18262,6 +18349,9 @@
         if (locationIsVendor(codePathString)) {
             scanFlags |= SCAN_AS_VENDOR;
         }
+        if (locationIsProduct(codePathString)) {
+            scanFlags |= SCAN_AS_PRODUCT;
+        }
 
         final File codePath = new File(codePathString);
         final PackageParser.Package pkg =
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 47cd813..686c4a5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1555,6 +1555,15 @@
         }
     }
 
+    private boolean isProductApp(String pkg) {
+        try {
+            final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+            return info != null && info.applicationInfo.isProduct();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     private int runGetPrivappPermissions() {
         final String pkg = getNextArg();
         if (pkg == null) {
@@ -1562,9 +1571,14 @@
             return 1;
         }
 
-        ArraySet<String> privAppPermissions = isVendorApp(pkg) ?
-                SystemConfig.getInstance().getVendorPrivAppPermissions(pkg)
-                    : SystemConfig.getInstance().getPrivAppPermissions(pkg);
+        ArraySet<String> privAppPermissions = null;
+        if (isVendorApp(pkg)) {
+            privAppPermissions = SystemConfig.getInstance().getVendorPrivAppPermissions(pkg);
+        } else if (isProductApp(pkg)) {
+            privAppPermissions = SystemConfig.getInstance().getProductPrivAppPermissions(pkg);
+        } else {
+            privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
+        }
 
         getOutPrintWriter().println(privAppPermissions == null
                 ? "{}" : privAppPermissions.toString());
@@ -1578,9 +1592,14 @@
             return 1;
         }
 
-        ArraySet<String> privAppPermissions = isVendorApp(pkg) ?
-                SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg)
-                    : SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
+        ArraySet<String> privAppPermissions = null;
+        if (isVendorApp(pkg)) {
+            privAppPermissions = SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg);
+        } else if (isProductApp(pkg)) {
+            privAppPermissions = SystemConfig.getInstance().getProductPrivAppDenyPermissions(pkg);
+        } else {
+            privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
+        }
 
         getOutPrintWriter().println(privAppPermissions == null
                 ? "{}" : privAppPermissions.toString());
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 2a2430c..3e2bd4a 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -173,6 +173,10 @@
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
     }
 
+    public boolean isProduct() {
+        return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+    }
+
     public boolean isForwardLocked() {
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
     }
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 46ba006..7c92045 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -62,6 +62,7 @@
                 & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
                 | ApplicationInfo.PRIVATE_FLAG_OEM
                 | ApplicationInfo.PRIVATE_FLAG_VENDOR
+                | ApplicationInfo.PRIVATE_FLAG_PRODUCT
                 | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK
                 | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
     }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 8ce412e..5e9019d 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -851,6 +851,8 @@
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM;
         pkgSetting.pkgPrivateFlags |=
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR;
+        pkgSetting.pkgPrivateFlags |=
+                pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT;
         pkgSetting.primaryCpuAbiString = primaryCpuAbi;
         pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
         if (childPkgNames != null) {
@@ -4397,6 +4399,7 @@
             ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER",
             ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY",
             ApplicationInfo.PRIVATE_FLAG_VENDOR, "VENDOR",
+            ApplicationInfo.PRIVATE_FLAG_PRODUCT, "PRODUCT",
             ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD",
     };
 
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6e07eaa..e2123c2 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1215,6 +1215,10 @@
         if (dir.isDirectory() && dir.canRead()) {
             Collections.addAll(ret, dir.listFiles());
         }
+        dir = new File(Environment.getProductDirectory(), "etc/default-permissions");
+        if (dir.isDirectory() && dir.canRead()) {
+            Collections.addAll(ret, dir.listFiles());
+        }
         return ret.isEmpty() ? null : ret.toArray(new File[0]);
     }
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 786b998..cb3b107 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -954,9 +954,16 @@
      * <p>This handles parent/child apps.
      */
     private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) {
-        ArraySet<String> wlPermissions = pkg.isVendor() ?
-                SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName)
-                    : SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName);
+        ArraySet<String> wlPermissions = null;
+        if (pkg.isVendor()) {
+            wlPermissions =
+                    SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName);
+        } else if (pkg.isProduct()) {
+            wlPermissions =
+                    SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName);
+        } else {
+            wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName);
+        }
         // Let's check if this package is whitelisted...
         boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm);
         // If it's not, we'll also tail-recurse to the parent.
@@ -979,11 +986,17 @@
                 // Only report violations for apps on system image
                 if (!mSystemReady && !pkg.isUpdatedSystemApp()) {
                     // it's only a reportable violation if the permission isn't explicitly denied
-                    final ArraySet<String> deniedPermissions = pkg.isVendor() ?
-                            SystemConfig.getInstance()
-                                    .getVendorPrivAppDenyPermissions(pkg.packageName)
-                            : SystemConfig.getInstance()
-                                    .getPrivAppDenyPermissions(pkg.packageName);
+                    ArraySet<String> deniedPermissions = null;
+                    if (pkg.isVendor()) {
+                        deniedPermissions = SystemConfig.getInstance()
+                                .getVendorPrivAppDenyPermissions(pkg.packageName);
+                    } else if (pkg.isProduct()) {
+                        deniedPermissions = SystemConfig.getInstance()
+                                .getProductPrivAppDenyPermissions(pkg.packageName);
+                    } else {
+                        deniedPermissions = SystemConfig.getInstance()
+                                .getPrivAppDenyPermissions(pkg.packageName);
+                    }
                     final boolean permissionViolation =
                             deniedPermissions == null || !deniedPermissions.contains(perm);
                     if (permissionViolation) {
diff --git a/tests/libs-permissions/Android.mk b/tests/libs-permissions/Android.mk
new file mode 100644
index 0000000..eb38623
--- /dev/null
+++ b/tests/libs-permissions/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.test.libs.product
+LOCAL_PRODUCT_MODULE := true
+LOCAL_SRC_FILES := $(call all-java-files-under, product/java)
+LOCAL_REQUIRED_MODULES := com.android.test.libs.product.xml
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.test.libs.product.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions
+LOCAL_SRC_FILES:= product/com.android.test.libs.product.xml
+include $(BUILD_PREBUILT)
diff --git a/tests/libs-permissions/product/com.android.test.libs.product.xml b/tests/libs-permissions/product/com.android.test.libs.product.xml
new file mode 100644
index 0000000..0a955e9
--- /dev/null
+++ b/tests/libs-permissions/product/com.android.test.libs.product.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<permissions>
+    <library name="com.android.test.libs.product"
+            file="/product/framework/com.android.test.libs.product.jar" />
+</permissions>
diff --git a/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java b/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java
new file mode 100644
index 0000000..f49b46e
--- /dev/null
+++ b/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.libs.product;
+
+/**
+ * Test class for product libs.
+ */
+public class LibsProductTest {
+
+    /**
+     * Dummpy method for testing.
+     */
+    public static void test() {
+    }
+}
diff --git a/tests/privapp-permissions/Android.mk b/tests/privapp-permissions/Android.mk
index b001c8c..3c80ad8 100644
--- a/tests/privapp-permissions/Android.mk
+++ b/tests/privapp-permissions/Android.mk
@@ -29,3 +29,17 @@
 LOCAL_SRC_FILES:= vendor/privapp-permissions-test.xml
 include $(BUILD_PREBUILT)
 
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := ProductPrivAppPermissionTest
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MANIFEST_FILE := product/AndroidManifest.xml
+LOCAL_PRODUCT_MODULE := true
+LOCAL_REQUIRED_MODULES := productprivapp-permissions-test.xml
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := productprivapp-permissions-test.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions
+LOCAL_SRC_FILES:= product/privapp-permissions-test.xml
+include $(BUILD_PREBUILT)
diff --git a/tests/privapp-permissions/product/AndroidManifest.xml b/tests/privapp-permissions/product/AndroidManifest.xml
new file mode 100644
index 0000000..3d9415c
--- /dev/null
+++ b/tests/privapp-permissions/product/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.framework.permission.privapp.tests.product">
+
+    <!-- MANAGE_USB is signature|privileged -->
+    <uses-permission android:name="android.permission.MANAGE_USB"/>
+</manifest>
diff --git a/tests/privapp-permissions/product/privapp-permissions-test.xml b/tests/privapp-permissions/product/privapp-permissions-test.xml
new file mode 100644
index 0000000..f298f9d
--- /dev/null
+++ b/tests/privapp-permissions/product/privapp-permissions-test.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+    <privapp-permissions package="com.android.framework.permission.privapp.tests.product">
+        <permission name="android.permission.MANAGE_USB"/>
+    </privapp-permissions>
+</permissions>
diff --git a/tools/incident_report/main.cpp b/tools/incident_report/main.cpp
index bd1b973..302d739 100644
--- a/tools/incident_report/main.cpp
+++ b/tools/incident_report/main.cpp
@@ -452,9 +452,10 @@
     bool adbIncidentWorkaround = true;
     pid_t childPid = -1;
     vector<string> sections;
+    const char* privacy = NULL;
 
     int opt;
-    while ((opt = getopt(argc, argv, "bhi:o:s:tw")) != -1) {
+    while ((opt = getopt(argc, argv, "bhi:o:s:twp:")) != -1) {
         switch (opt) {
             case 'b':
                 outputFormat = OUTPUT_PROTO;
@@ -477,6 +478,9 @@
             case 'w':
                 adbIncidentWorkaround = false;
                 break;
+            case 'p':
+                privacy = optarg;
+                break;
             default:
                 usage(stderr);
                 return 1;
@@ -526,7 +530,7 @@
             }
 
             // TODO: This is what the real implementation will be...
-            char const** args = (char const**)malloc(sizeof(char*) * (6 + sections.size()));
+            char const** args = (char const**)malloc(sizeof(char*) * (8 + sections.size()));
             int argpos = 0;
             args[argpos++] = "adb";
             if (adbSerial != NULL) {
@@ -535,6 +539,10 @@
             }
             args[argpos++] = "shell";
             args[argpos++] = "incident";
+            if (privacy != NULL) {
+                args[argpos++] = "-p";
+                args[argpos++] = privacy;
+            }
             for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
                 args[argpos++] = it->c_str();
             }