Merge "Update ImageDecoder docs regarding Files" into rvc-dev
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c75870e..eea1d69 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -7513,7 +7513,15 @@
             try {
                 super.rename(oldPath, newPath);
             } catch (ErrnoException e) {
-                if (e.errno == OsConstants.EXDEV && oldPath.startsWith("/storage/")) {
+                // On emulated volumes, we have bind mounts for /Android/data and
+                // /Android/obb, which prevents move from working across those directories
+                // and other directories on the filesystem. To work around that, try to
+                // recover by doing a copy instead.
+                // Note that we only do this for "/storage/emulated", because public volumes
+                // don't have these bind mounts, neither do private volumes that are not
+                // the primary storage.
+                if (e.errno == OsConstants.EXDEV && oldPath.startsWith("/storage/emulated")
+                        && newPath.startsWith("/storage/emulated")) {
                     Log.v(TAG, "Recovering failed rename " + oldPath + " to " + newPath);
                     try {
                         Files.move(new File(oldPath).toPath(), new File(newPath).toPath(),
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 2f048c9..a50a522 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -68,6 +68,7 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Predicate;
 import java.util.regex.Pattern;
 
 /**
@@ -381,17 +382,51 @@
         return result;
     }
 
+    /**
+     * This method is similar to
+     * {@link DocumentsProvider#queryChildDocuments(String, String[], String)}. This method returns
+     * all children documents including hidden directories/files.
+     *
+     * <p>
+     * In a scoped storage world, access to "Android/data" style directories are hidden for privacy
+     * reasons. This method may show privacy sensitive data, so its usage should only be in
+     * restricted modes.
+     *
+     * @param parentDocumentId the directory to return children for.
+     * @param projection list of {@link Document} columns to put into the
+     *            cursor. If {@code null} all supported columns should be
+     *            included.
+     * @param sortOrder how to order the rows, formatted as an SQL
+     *            {@code ORDER BY} clause (excluding the ORDER BY itself).
+     *            Passing {@code null} will use the default sort order, which
+     *            may be unordered. This ordering is a hint that can be used to
+     *            prioritize how data is fetched from the network, but UI may
+     *            always enforce a specific ordering
+     * @throws FileNotFoundException when parent document doesn't exist or query fails
+     */
+    protected Cursor queryChildDocumentsShowAll(
+            String parentDocumentId, String[] projection, String sortOrder)
+            throws FileNotFoundException {
+        return queryChildDocuments(parentDocumentId, projection, sortOrder, File -> true);
+    }
+
     @Override
     public Cursor queryChildDocuments(
             String parentDocumentId, String[] projection, String sortOrder)
             throws FileNotFoundException {
+        // Access to some directories is hidden for privacy reasons.
+        return queryChildDocuments(parentDocumentId, projection, sortOrder, this::shouldShow);
+    }
 
+    private Cursor queryChildDocuments(
+            String parentDocumentId, String[] projection, String sortOrder,
+            @NonNull Predicate<File> filter) throws FileNotFoundException {
         final File parent = getFileForDocId(parentDocumentId);
         final MatrixCursor result = new DirectoryCursor(
                 resolveProjection(projection), parentDocumentId, parent);
         if (parent.isDirectory()) {
             for (File file : FileUtils.listFilesOrEmpty(parent)) {
-                if (!shouldHide(file)) {
+                if (filter.test(file)) {
                     includeFile(result, null, file);
                 }
             }
@@ -617,6 +652,10 @@
         return (PATTERN_HIDDEN_PATH.matcher(file.getAbsolutePath()).matches());
     }
 
+    private boolean shouldShow(@NonNull File file) {
+        return !shouldHide(file);
+    }
+
     protected boolean shouldBlockFromTree(@NonNull String docId) {
         return false;
     }
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index b5e2213..c4d27ec 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -23,8 +23,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.media.projection.IMediaProjection;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -86,6 +84,12 @@
      * capture request. Will be null if the result from the
      * startActivityForResult() is anything other than RESULT_OK.
      *
+     * Starting from Android {@link android.os.Build.VERSION_CODES#R}, if your application requests
+     * the {@link android.Manifest.permission#SYSTEM_ALERT_WINDOW} permission, and the
+     * user has not explicitly denied it, the permission will be automatically granted until the
+     * projection is stopped. This allows for user controls to be displayed on top of the screen
+     * being captured.
+     *
      * @param resultCode The result code from {@link android.app.Activity#onActivityResult(int,
      * int, android.content.Intent)}
      * @param resultData The resulting data from {@link android.app.Activity#onActivityResult(int,
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 0c70e10..8f919c3 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -275,6 +275,13 @@
         return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
     }
 
+    @Override
+    public Cursor queryChildDocumentsForManage(
+            String parentDocId, String[] projection, String sortOrder)
+            throws FileNotFoundException {
+        return queryChildDocumentsShowAll(parentDocId, projection, sortOrder);
+    }
+
     /**
      * Check that the directory is the root of storage or blocked file from tree.
      *
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 53f9ebc..1ed5cd8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -2207,13 +2207,7 @@
         @Override
         public void setHdmiCecVolumeControlEnabled(final boolean isHdmiCecVolumeControlEnabled) {
             enforceAccessPermission();
-            runOnServiceThread(new Runnable() {
-                @Override
-                public void run() {
-                    HdmiControlService.this.setHdmiCecVolumeControlEnabled(
-                            isHdmiCecVolumeControlEnabled);
-                }
-            });
+            HdmiControlService.this.setHdmiCecVolumeControlEnabled(isHdmiCecVolumeControlEnabled);
         }
 
         @Override
@@ -3014,7 +3008,6 @@
     }
 
     void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) {
-        assertRunOnServiceThread();
         synchronized (mLock) {
             mHdmiCecVolumeControlEnabled = isHdmiCecVolumeControlEnabled;
 
@@ -3030,7 +3023,6 @@
     }
 
     boolean isHdmiCecVolumeControlEnabled() {
-        assertRunOnServiceThread();
         synchronized (mLock) {
             return mHdmiCecVolumeControlEnabled;
         }
diff --git a/services/core/java/com/android/server/lights/TEST_MAPPING b/services/core/java/com/android/server/lights/TEST_MAPPING
new file mode 100644
index 0000000..f868ea0
--- /dev/null
+++ b/services/core/java/com/android/server/lights/TEST_MAPPING
@@ -0,0 +1,21 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsHardwareTestCases",
+      "options": [
+        {"include-filter": "com.android.hardware.lights"},
+        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+        {"exclude-annotation": "androidx.test.filters.LargeTest"},
+        {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+      ]
+    },
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {"include-filter": "com.android.server.lights"},
+        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+        {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+      ]
+    }
+  ]
+}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 9e509f4..1a749b3 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -22,6 +22,7 @@
 import android.app.IProcessObserver;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ServiceInfo;
@@ -43,6 +44,7 @@
 import android.util.ArrayMap;
 import android.util.Slog;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -399,11 +401,12 @@
         public final UserHandle userHandle;
         private final int mTargetSdkVersion;
         private final boolean mIsPrivileged;
+        private final int mType;
 
         private IMediaProjectionCallback mCallback;
         private IBinder mToken;
         private IBinder.DeathRecipient mDeathEater;
-        private int mType;
+        private boolean mRestoreSystemAlertWindow;
 
         MediaProjection(int type, int uid, String packageName, int targetSdkVersion,
                 boolean isPrivileged) {
@@ -494,6 +497,35 @@
                             "MediaProjectionCallbacks must be valid, aborting MediaProjection", e);
                     return;
                 }
+                if (mType == MediaProjectionManager.TYPE_SCREEN_CAPTURE) {
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        // We allow an app running a current screen capture session to use
+                        // SYSTEM_ALERT_WINDOW for the duration of the session, to enable
+                        // them to overlay their UX on top of what is being captured.
+                        // We only do this if the app requests the permission, and the appop
+                        // is in its default state (the user has neither explicitly allowed nor
+                        // disallowed it).
+                        final PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(
+                                packageName, PackageManager.GET_PERMISSIONS,
+                                UserHandle.getUserId(uid));
+                        if (ArrayUtils.contains(packageInfo.requestedPermissions,
+                                Manifest.permission.SYSTEM_ALERT_WINDOW)) {
+                            final int currentMode = mAppOps.unsafeCheckOpRawNoThrow(
+                                    AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName);
+                            if (currentMode == AppOpsManager.MODE_DEFAULT) {
+                                mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid,
+                                        packageName, AppOpsManager.MODE_ALLOWED);
+                                mRestoreSystemAlertWindow = true;
+                            }
+                        }
+                    } catch (PackageManager.NameNotFoundException e) {
+                        Slog.w(TAG, "Package not found, aborting MediaProjection", e);
+                        return;
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
                 startProjectionLocked(this);
             }
         }
@@ -507,6 +539,24 @@
                             + "pid=" + Binder.getCallingPid() + ")");
                     return;
                 }
+                if (mRestoreSystemAlertWindow) {
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        // Put the appop back how it was, unless it has been changed from what
+                        // we set it to.
+                        // Note that WindowManager takes care of removing any existing overlay
+                        // windows when we do this.
+                        final int currentMode = mAppOps.unsafeCheckOpRawNoThrow(
+                                AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName);
+                        if (currentMode == AppOpsManager.MODE_ALLOWED) {
+                            mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName,
+                                    AppOpsManager.MODE_DEFAULT);
+                        }
+                        mRestoreSystemAlertWindow = false;
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
                 stopProjectionLocked(this);
                 mToken.unlinkToDeath(mDeathEater, 0);
                 mToken = null;
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 317bb43..d02be88 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -60,7 +60,37 @@
     private final IntArray mShowingTransientTypes = new IntArray();
 
     /** For resetting visibilities of insets sources. */
-    private final InsetsControlTarget mDummyControlTarget = new InsetsControlTarget() { };
+    private final InsetsControlTarget mDummyControlTarget = new InsetsControlTarget() {
+
+        @Override
+        public void notifyInsetsControlChanged() {
+            boolean hasLeash = false;
+            final InsetsSourceControl[] controls =
+                    mStateController.getControlsForDispatch(this);
+            if (controls == null) {
+                return;
+            }
+            for (InsetsSourceControl control : controls) {
+                final @InternalInsetsType int type = control.getType();
+                if (mShowingTransientTypes.indexOf(type) != -1) {
+                    // The visibilities of transient bars will be handled with animations.
+                    continue;
+                }
+                final SurfaceControl leash = control.getLeash();
+                if (leash != null) {
+                    hasLeash = true;
+
+                    // We use alpha to control the visibility here which aligns the logic at
+                    // SurfaceAnimator.createAnimationLeash
+                    mDisplayContent.getPendingTransaction().setAlpha(
+                            leash, InsetsState.getDefaultVisibility(type) ? 1f : 0f);
+                }
+            }
+            if (hasLeash) {
+                mDisplayContent.scheduleAnimation();
+            }
+        }
+    };
 
     private WindowState mFocusedWin;
     private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);