Merge "Protect runtime storage mount points." into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index 05e494b..ac34c59 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3412,6 +3412,7 @@
     method public boolean onSearchRequested(android.view.SearchEvent);
     method public boolean onSearchRequested();
     method protected void onStart();
+    method public void onStateNotSaved();
     method protected void onStop();
     method protected void onTitleChanged(java.lang.CharSequence, int);
     method public boolean onTouchEvent(android.view.MotionEvent);
diff --git a/api/system-current.txt b/api/system-current.txt
index d9702ac..7987803 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3516,6 +3516,7 @@
     method public boolean onSearchRequested(android.view.SearchEvent);
     method public boolean onSearchRequested();
     method protected void onStart();
+    method public void onStateNotSaved();
     method protected void onStop();
     method protected void onTitleChanged(java.lang.CharSequence, int);
     method public boolean onTouchEvent(android.view.MotionEvent);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3c8af0d..2cb3f39 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1172,6 +1172,16 @@
     }
 
     /**
+     * Called when an {@link #onResume} is coming up, prior to other pre-resume callbacks
+     * such as {@link #onNewIntent} and {@link #onActivityResult}.  This is primarily intended
+     * to give the activity a hint that its state is no longer saved -- it will generally
+     * be called after {@link #onSaveInstanceState} and prior to the activity being
+     * resumed/started again.
+     */
+    public void onStateNotSaved() {
+    }
+
+    /**
      * Called after {@link #onRestoreInstanceState}, {@link #onRestart}, or
      * {@link #onPause}, for your activity to start interacting with the user.
      * This is a good place to begin animations, open exclusive-access devices
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2b4d03b..fd88a05 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3079,6 +3079,7 @@
                 r.activity.mStartedActivity = false;
             }
             try {
+                r.activity.onStateNotSaved();
                 r.activity.mFragments.noteStateNotSaved();
                 if (r.pendingIntents != null) {
                     deliverNewIntents(r, r.pendingIntents);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index b4cbf35..f9fa027 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -105,7 +105,10 @@
     /** View that handles event dispatch and content transitions. */
     private PopupDecorView mDecorView;
 
-    /** The contents of the popup. */
+    /** View that holds the background and may animate during a transition. */
+    private View mBackgroundView;
+
+    /** The contents of the popup. May be identical to the background view. */
     private View mContentView;
 
     private boolean mFocusable;
@@ -1111,18 +1114,18 @@
         if (aboveAnchor != mAboveAnchor) {
             mAboveAnchor = aboveAnchor;
 
-            if (mBackground != null) {
-                // If the background drawable provided was a StateListDrawable with above-anchor
-                // and below-anchor states, use those. Otherwise rely on refreshDrawableState to
-                // do the job.
+            if (mBackground != null && mBackgroundView != null) {
+                // If the background drawable provided was a StateListDrawable
+                // with above-anchor and below-anchor states, use those.
+                // Otherwise, rely on refreshDrawableState to do the job.
                 if (mAboveAnchorBackgroundDrawable != null) {
                     if (mAboveAnchor) {
-                        mDecorView.setBackground(mAboveAnchorBackgroundDrawable);
+                        mBackgroundView.setBackground(mAboveAnchorBackgroundDrawable);
                     } else {
-                        mDecorView.setBackground(mBelowAnchorBackgroundDrawable);
+                        mBackgroundView.setBackground(mBelowAnchorBackgroundDrawable);
                     }
                 } else {
-                    mDecorView.refreshDrawableState();
+                    mBackgroundView.refreshDrawableState();
                 }
             }
         }
@@ -1164,22 +1167,21 @@
 
         // When a background is available, we embed the content view within
         // another view that owns the background drawable.
-        final View backgroundView;
         if (mBackground != null) {
-            backgroundView = createBackgroundView(mContentView);
-            backgroundView.setBackground(mBackground);
+            mBackgroundView = createBackgroundView(mContentView);
+            mBackgroundView.setBackground(mBackground);
         } else {
-            backgroundView = mContentView;
+            mBackgroundView = mContentView;
         }
 
-        mDecorView = createDecorView(backgroundView);
+        mDecorView = createDecorView(mBackgroundView);
 
         // The background owner should be elevated so that it casts a shadow.
-        backgroundView.setElevation(mElevation);
+        mBackgroundView.setElevation(mElevation);
 
         // We may wrap that in another view, so we'll need to manually specify
         // the surface insets.
-        final int surfaceInset = (int) Math.ceil(backgroundView.getZ() * 2);
+        final int surfaceInset = (int) Math.ceil(mBackgroundView.getZ() * 2);
         p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
         p.hasManualSurfaceInsets = true;
 
@@ -1650,6 +1652,7 @@
         // This needs to stay until after all transitions have ended since we
         // need the reference to cancel transitions in preparePopup().
         mDecorView = null;
+        mBackgroundView = null;
         mIsTransitioningToDismiss = false;
     }
 
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index d954b71..55493c3 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -28,6 +28,7 @@
 public class MetricsLogger implements MetricsConstants {
     // Temporary constants go here, to await migration to MetricsConstants.
     // next value is 239;
+    public static final int ACTION_ASSIST_LONG_PRESS = 239;
 
     public static void visible(Context context, int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 6104264..fef65ee 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.util.SparseIntArray;
 
+import java.util.TreeSet;
+
 /**
  * Class to provide information about the audio devices.
  */
@@ -109,6 +111,14 @@
      * A device type connected over IP.
      */
     public static final int TYPE_IP               = 20;
+    /**
+     * @hide
+     * A remote-submix device.
+     * We need this for CTS, but it is not part of the external API.
+     * FIXME It has been suggested that CTS should only be testing public APIs.
+     *   Consider this for a public API.
+     */
+    public static final int TYPE_REMOTE_SUBMIX    = 0x7FFF;
 
     private final AudioDevicePort mPort;
 
@@ -193,13 +203,24 @@
      * Note: an empty array indicates that the device supports arbitrary channel counts.
      */
     public @NonNull int[] getChannelCounts() {
-        int[] masks = getChannelMasks();
-        int[] counts = new int[masks.length];
-        // TODO: consider channel index masks
-        for (int mask_index = 0; mask_index < masks.length; mask_index++) {
-            counts[mask_index] = isSink()
-                    ? AudioFormat.channelCountFromOutChannelMask(masks[mask_index])
-                    : AudioFormat.channelCountFromInChannelMask(masks[mask_index]);
+        TreeSet<Integer> countSet = new TreeSet<Integer>();
+
+        // Channel Masks
+        for (int mask : getChannelMasks()) {
+            countSet.add(isSink() ?
+                    AudioFormat.channelCountFromOutChannelMask(mask)
+                    : AudioFormat.channelCountFromInChannelMask(mask));
+        }
+
+        // Index Masks
+        for (int index_mask : getChannelIndexMasks()) {
+            countSet.add(Integer.bitCount(index_mask));
+        }
+
+        int[] counts = new int[countSet.size()];
+        int index = 0;
+        for (int count : countSet) {
+            counts[index++] = count; 
         }
         return counts;
     }
@@ -265,6 +286,7 @@
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, TYPE_FM);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, TYPE_AUX_LINE);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_IP, TYPE_IP);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX);
 
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
@@ -282,10 +304,7 @@
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, TYPE_LINE_DIGITAL);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_IP, TYPE_IP);
-
-        // not covered here, legacy
-        //AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
-        //AudioSystem.DEVICE_IN_REMOTE_SUBMIX
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX);
 
         // privileges mapping to output device
         EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 86755d1..6c0deb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1056,6 +1056,7 @@
             if (shouldDisableNavbarGestures()) {
                 return false;
             }
+            MetricsLogger.action(mContext, MetricsLogger.ACTION_ASSIST_LONG_PRESS);
             mAssistManager.startAssist(new Bundle() /* args */);
             awakenDreams();
             if (mNavigationBarView != null) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 7e2ad29..9da30bf 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -786,7 +786,8 @@
     }
 
     boolean isLockTaskWhitelistedLocked() {
-        if (mCallingPackage == null) {
+        String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
+        if (pkg == null) {
             return false;
         }
         String[] packages = mService.mLockTaskPackages.get(userId);
@@ -794,7 +795,7 @@
             return false;
         }
         for (int i = packages.length - 1; i >= 0; --i) {
-            if (mCallingPackage.equals(packages[i])) {
+            if (pkg.equals(packages[i])) {
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 3227ef8..71a2d59 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -34,6 +34,7 @@
 import android.provider.ContactsContract;
 import android.provider.MediaStore;
 import android.provider.Telephony.Sms.Intents;
+import android.security.Credentials;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -298,6 +299,15 @@
                 grantRuntimePermissionsLPw(storagePackage, STORAGE_PERMISSIONS, userId);
             }
 
+            // CertInstaller
+            Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION);
+            PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackageLPr(
+                    certInstallerIntent, userId);
+            if (certInstallerPackage != null
+                    && doesPackageSupportRuntimePermissions(certInstallerPackage)) {
+                grantRuntimePermissionsLPw(certInstallerPackage, STORAGE_PERMISSIONS, true, userId);
+            }
+
             // Dialer
             if (dialerAppPackageNames == null) {
                 Intent dialerIntent = new Intent(Intent.ACTION_DIAL);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 04d6d98..1788e88 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -48,6 +48,7 @@
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.IResultReceiver;
 import com.android.server.LocalServices;
 import com.android.server.statusbar.StatusBarManagerInternal;
@@ -225,6 +226,7 @@
                         mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
                         && structureEnabled) {
                     try {
+                        MetricsLogger.count(mContext, "assist_with_context", 1);
                         if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
                                 mAssistReceiver, activityToken)) {
                             needDisclosure = true;
@@ -249,6 +251,7 @@
                         mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
                         && screenshotEnabled) {
                     try {
+                        MetricsLogger.count(mContext, "assist_with_screen", 1);
                         needDisclosure = true;
                         mIWindowManager.requestAssistScreenshot(mScreenshotReceiver);
                     } catch (RemoteException e) {