Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cd66c686 authored by Naomi Musgrave's avatar Naomi Musgrave
Browse files

[MediaProjection] Introduce hidden/visible callback.

Notify client when the captured content becomes hidden, or
at least partially visible. This is only relevant if the user
selected per-app capture, and the captured app becomes visible
or hidden.

Test: atest WmTests:ContentRecorderTests
Test: atest WmTests:WindowContainerTests
Bug: 260083492
API-Coverage-Bug: 260083492
Change-Id: I29240bef2a4d08b9fea45cd7cf07a1a7ca203505
parent ccb92936
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -25544,6 +25544,7 @@ package android.media.projection {
  public abstract static class MediaProjection.Callback {
    ctor public MediaProjection.Callback();
    method public void onCapturedContentResize(int, int);
    method public void onCapturedContentVisibilityChanged(boolean);
    method public void onStop();
  }
+6 −12
Original line number Diff line number Diff line
@@ -1627,12 +1627,6 @@
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "-576580969": {
      "message": "viewServerWindowCommand: bootFinished() failed.",
      "level": "WARN",
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "-576070986": {
      "message": "Performing post-rotate rotation after seamless rotation",
      "level": "INFO",
@@ -1975,6 +1969,12 @@
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "-254406860": {
      "message": "Unable to tell MediaProjectionManagerService about visibility change on the active projection: %s",
      "level": "ERROR",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "-251259736": {
      "message": "No longer freezing: %s",
      "level": "VERBOSE",
@@ -4153,12 +4153,6 @@
      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
    },
    "1903353011": {
      "message": "notifyAppStopped: %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_ADD_REMOVE",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "1912291550": {
      "message": "Sleep still waiting to pause %s",
      "level": "VERBOSE",
+1 −0
Original line number Diff line number Diff line
@@ -20,4 +20,5 @@ package android.media.projection;
oneway interface IMediaProjectionCallback {
    void onStop();
    void onCapturedContentResize(int width, int height);
    void onCapturedContentVisibilityChanged(boolean isVisible);
}
+5 −1
Original line number Diff line number Diff line
@@ -47,6 +47,10 @@ interface IMediaProjectionManager {
            + ".permission.MANAGE_MEDIA_PROJECTION)")
    void notifyActiveProjectionCapturedContentResized(int width, int height);

    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
                + ".permission.MANAGE_MEDIA_PROJECTION)")
    void notifyActiveProjectionCapturedContentVisibilityChanged(boolean isVisible);

    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
                + ".permission.MANAGE_MEDIA_PROJECTION)")
    void addCallback(IMediaProjectionWatcherCallback callback);
+54 −7
Original line number Diff line number Diff line
@@ -66,13 +66,20 @@ public final class MediaProjection {
        }
    }

    /** Register a listener to receive notifications about when the {@link
     * MediaProjection} changes state.
    /**
     * Register a listener to receive notifications about when the {@link MediaProjection} or
     * captured content changes state.
     * <p>
     * The callback should be registered before invoking
     * {@link #createVirtualDisplay(String, int, int, int, int, Surface, VirtualDisplay.Callback,
     * Handler)}
     * to ensure that any notifications on the callback are not missed.
     * </p>
     *
     * @param callback The callback to call.
     * @param handler  The handler on which the callback should be invoked, or
     *                 null if the callback should be invoked on the calling thread's looper.
     *
     * @throws IllegalArgumentException If the given callback is null.
     * @see #unregisterCallback
     */
    public void registerCallback(Callback callback, Handler handler) {
@@ -85,10 +92,11 @@ public final class MediaProjection {
        mCallbacks.put(callback, new CallbackRecord(callback, handler));
    }

    /** Unregister a MediaProjection listener.
    /**
     * Unregister a {@link MediaProjection} listener.
     *
     * @param callback The callback to unregister.
     *
     * @throws IllegalArgumentException If the given callback is null.
     * @see #registerCallback
     */
    public void unregisterCallback(Callback callback) {
@@ -283,6 +291,34 @@ public final class MediaProjection {
         * }</pre>
         */
        public void onCapturedContentResize(int width, int height) { }

        /**
         * Indicates the visibility of the captured region has changed. Called immediately after
         * capture begins with the initial visibility state, and when visibility changes. Provides
         * the app with accurate state for presenting its own UI. The application can take advantage
         * of this by showing or hiding the captured content, based on if the captured region is
         * currently visible to the user.
         * <p>
         * For example, if the user elected to capture a single app (from the activity shown from
         * {@link MediaProjectionManager#createScreenCaptureIntent()}), the callback may be
         * triggered for the following reasons:
         * <ul>
         *     <li>
         *         The captured region may become visible ({@code isVisible} with value
         *         {@code true}), because the captured app is at least partially visible. This may
         *         happen if the captured app was previously covered by another app. The other app
         *         moves to show at least some portion of the captured app.
         *     </li>
         *     <li>
         *         The captured region may become invisible ({@code isVisible} with value
         *         {@code false}) if it is entirely hidden. This may happen if the captured app is
         *         entirely covered by another app, or the user navigates away from the captured
         *         app.
         *     </li>
         * </ul>
         * </p>
         */
        public void onCapturedContentVisibilityChanged(boolean isVisible) { }
    }

    private final class MediaProjectionCallback extends IMediaProjectionCallback.Stub {
@@ -299,6 +335,13 @@ public final class MediaProjection {
                cbr.onCapturedContentResize(width, height);
            }
        }

        @Override
        public void onCapturedContentVisibilityChanged(boolean isVisible) {
            for (CallbackRecord cbr : mCallbacks.values()) {
                cbr.onCapturedContentVisibilityChanged(isVisible);
            }
        }
    }

    private final static class CallbackRecord {
@@ -322,5 +365,9 @@ public final class MediaProjection {
        public void onCapturedContentResize(int width, int height) {
            mHandler.post(() -> mCallback.onCapturedContentResize(width, height));
        }

        public void onCapturedContentVisibilityChanged(boolean isVisible) {
            mHandler.post(() -> mCallback.onCapturedContentVisibilityChanged(isVisible));
        }
    }
}
Loading