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

Commit 0e75779b authored by Omar Eissa's avatar Omar Eissa Committed by Ahmed Ibrahim
Browse files

Create Screenshot Detection APIs

This is a followup on ag/19854404

The APIs are used on a per Activity granularity, a client can register
their callback via: `registerScreenCaptureCallback(mExecutor, mCallback);` on Activity

The activity token is used to communiate from the client side to the
ActivityTaskManager and ActivityRecord on the server side. The WMS will receieve a notification when the hardware chord for screenshots is triggered by the user, it would then find all activites that have visible windows and trigger the callbacks registered on all of them.
for more details, see go/screenshot-detection-dd

Bug: 245115438
Test:  CTS tests && Manual
Change-Id: I27bf708ac86187f066971b1b01c5b308f78a01b3
parent 1fa760d1
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -4319,6 +4319,7 @@ package android.app {
    method public void recreate();
    method public void registerActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks);
    method public void registerForContextMenu(android.view.View);
    method @RequiresPermission(android.Manifest.permission.DETECT_SCREEN_CAPTURE) public void registerScreenCaptureCallback(@NonNull java.util.concurrent.Executor, @NonNull android.app.Activity.ScreenCaptureCallback);
    method public boolean releaseInstance();
    method @Deprecated public final void removeDialog(int);
    method public void reportFullyDrawn();
@@ -4404,6 +4405,7 @@ package android.app {
    method public void triggerSearch(String, @Nullable android.os.Bundle);
    method public void unregisterActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks);
    method public void unregisterForContextMenu(android.view.View);
    method @RequiresPermission(android.Manifest.permission.DETECT_SCREEN_CAPTURE) public void unregisterScreenCaptureCallback(@NonNull android.app.Activity.ScreenCaptureCallback);
    field public static final int DEFAULT_KEYS_DIALER = 1; // 0x1
    field public static final int DEFAULT_KEYS_DISABLE = 0; // 0x0
    field public static final int DEFAULT_KEYS_SEARCH_GLOBAL = 4; // 0x4
@@ -4417,6 +4419,10 @@ package android.app {
    field public static final int RESULT_OK = -1; // 0xffffffff
  }
  public static interface Activity.ScreenCaptureCallback {
    method public void onScreenCaptured();
  }
  @Deprecated public class ActivityGroup extends android.app.Activity {
    ctor @Deprecated public ActivityGroup();
    ctor @Deprecated public ActivityGroup(boolean);
+1 −0
Original line number Diff line number Diff line
@@ -16640,6 +16640,7 @@ package android.view {
  public interface WindowManager extends android.view.ViewManager {
    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public android.graphics.Region getCurrentImeTouchRegion();
    method @NonNull public default java.util.List<android.content.ComponentName> notifyScreenshotListeners(int);
    method public default void registerTaskFpsCallback(@IntRange(from=0) int, @NonNull java.util.concurrent.Executor, @NonNull android.window.TaskFpsCallback);
    method public default void unregisterTaskFpsCallback(@NonNull android.window.TaskFpsCallback);
  }
+42 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.app;

import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.Manifest.permission.DETECT_SCREEN_CAPTURE;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -26,6 +27,7 @@ import static android.os.Process.myUid;
import static java.lang.Character.MIN_VALUE;

import android.annotation.CallSuper;
import android.annotation.CallbackExecutor;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.IntDef;
@@ -1016,6 +1018,7 @@ public class Activity extends ContextThemeWrapper
    private ComponentCallbacksController mCallbacksController;

    @Nullable private IVoiceInteractionManagerService mVoiceInteractionManagerService;
    private ScreenCaptureCallbackHandler mScreenCaptureCallbackHandler;

    private final WindowControllerCallback mWindowControllerCallback =
            new WindowControllerCallback() {
@@ -9222,4 +9225,43 @@ public class Activity extends ContextThemeWrapper
        }
        return mWindow.getOnBackInvokedDispatcher();
    }

    /**
     * Interface for observing screen captures of an {@link Activity}.
     */
    public interface ScreenCaptureCallback {
        /**
         * Called when one of the monitored activities is captured.
         * This is not invoked if the activity window
         * has {@link WindowManager.LayoutParams#FLAG_SECURE} set.
         */
        void onScreenCaptured();
    }

    /**
     * Registers a screen capture callback for this activity.
     * The callback will be triggered when a screen capture of this activity is attempted.
     * This callback will be executed on the thread of the passed {@code executor}.
     * For details, see {@link ScreenCaptureCallback#onScreenCaptured}.
     */
    @RequiresPermission(DETECT_SCREEN_CAPTURE)
    public void registerScreenCaptureCallback(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull ScreenCaptureCallback callback) {
        if (mScreenCaptureCallbackHandler == null) {
            mScreenCaptureCallbackHandler = new ScreenCaptureCallbackHandler(mToken);
        }
        mScreenCaptureCallbackHandler.registerScreenCaptureCallback(executor, callback);
    }


    /**
     * Unregisters a screen capture callback for this surface.
     */
    @RequiresPermission(DETECT_SCREEN_CAPTURE)
    public void unregisterScreenCaptureCallback(@NonNull ScreenCaptureCallback callback) {
        if (mScreenCaptureCallbackHandler != null) {
            mScreenCaptureCallbackHandler.unregisterScreenCaptureCallback(callback);
        }
    }
}
+20 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.app.IAppTask;
import android.app.IAssistDataReceiver;
import android.app.IInstrumentationWatcher;
import android.app.IProcessObserver;
import android.app.IScreenCaptureObserver;
import android.app.IServiceConnection;
import android.app.IStopUserCallback;
import android.app.ITaskStackListener;
@@ -354,4 +355,23 @@ interface IActivityTaskManager {
     */
    android.window.BackNavigationInfo startBackNavigation(
            in IWindowFocusObserver focusObserver, in BackAnimationAdapter adaptor);

    /**
     * registers a callback to be invoked when the screen is captured.
     *
     * @param observer callback to be registered.
     * @param activityToken The token for the activity to set the callback to.
     * @hide
     */
    void registerScreenCaptureObserver(IBinder activityToken, IScreenCaptureObserver observer);

    /**
     * unregisters the screen capture callback which was registered with
     * {@link #registerScreenCaptureObserver(ScreenCaptureObserver)}.
     *
     * @param observer callback to be unregistered.
     * @param activityToken The token for the activity to unset the callback from.
     * @hide
     */
    void unregisterScreenCaptureObserver(IBinder activityToken, IScreenCaptureObserver observer);
}
+22 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 android.app;

/** {@hide} */
interface IScreenCaptureObserver {
    oneway void onScreenCaptured();
}
Loading