Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions core/java/android/provider/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -13768,6 +13768,19 @@ public static boolean putFloatForUser(ContentResolver cr, String name, float val
*/
public static final String DISABLE_SECURE_WINDOWS = "disable_secure_windows";

/**

Whether to allow user-initiated screenshots of secure windows.

When this setting is set to a non-zero value, user-initiated screenshots
will capture content in windows with
{@link android.view.WindowManager.LayoutParams#FLAG_SECURE}.
Other FLAG_SECURE behaviors (recents thumbnails, casting, screen recording)
are preserved.
@hide */
public static final String FORCE_SCREENSHOT_SECURE_WINDOWS = "force_screenshot_secure_windows";


/**
* Controls if the adaptive authentication feature should be disabled, which
* will attempt to lock the device after a number of consecutive authentication
Expand Down
43 changes: 40 additions & 3 deletions services/core/java/com/android/server/wm/WindowManagerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
import static android.window.ScreenCapture.ScreenCaptureParams.CAPTURE_MODE_REQUIRE_OPTIMIZED;
import static android.window.ScreenCapture.ScreenCaptureParams.PROTECTED_CONTENT_POLICY_THROW_EXCEPTION;
import static android.window.ScreenCapture.ScreenCaptureParams.SECURE_CONTENT_POLICY_THROW_EXCEPTION;
import static android.window.ScreenCapture.ScreenCaptureParams.SECURE_CONTENT_POLICY_CAPTURE;
import static android.window.WindowProviderService.isWindowProviderService;

import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ADD_REMOVE;
Expand Down Expand Up @@ -835,6 +836,8 @@ final class SettingsObserver extends ContentObserver {
Settings.Secure.getUriFor(Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS);
private final Uri mDisableSecureWindowsUri =
Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS);
private final Uri mForceScreenshotSecureWindowsUri =
Settings.Secure.getUriFor(Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS);
private final Uri mMagnifyImeEnabledUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME);
private final Uri mPolicyControlUri =
Expand Down Expand Up @@ -869,6 +872,9 @@ public SettingsObserver() {
UserHandle.USER_ALL);
resolver.registerContentObserver(mDisableSecureWindowsUri, false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(mForceScreenshotSecureWindowsUri, false, this,
UserHandle.USER_ALL);

if (com.android.server.accessibility.Flags.enableMagnificationMagnifyNavBarAndIme()) {
resolver.registerContentObserver(mMagnifyImeEnabledUri, false, this,
UserHandle.USER_ALL);
Expand Down Expand Up @@ -934,6 +940,11 @@ public void onChange(boolean selfChange, Uri uri) {
return;
}

if (mForceScreenshotSecureWindowsUri.equals(uri)) {
updateForceScreenshotSecureWindows();
return;
}

if (mMagnifyImeEnabledUri.equals(uri)) {
updateMagnifyIme();
}
Expand Down Expand Up @@ -962,6 +973,7 @@ public void onChange(boolean selfChange, Uri uri) {
void loadSettings() {
updateMaximumObscuringOpacityForTouch();
updateDisableSecureWindows();
updateForceScreenshotSecureWindows();
updateMagnifyIme();
}

Expand Down Expand Up @@ -1072,6 +1084,19 @@ void updateDisableSecureWindows() {
}
}

void updateForceScreenshotSecureWindows() {

boolean forceScreenshotSecureWindows;
try {
forceScreenshotSecureWindows = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS, 0) != 0;
} catch (Settings.SettingNotFoundException e) {
forceScreenshotSecureWindows = false;
}
mForceScreenshotSecureWindows = forceScreenshotSecureWindows;
}

void updateMagnifyIme() {
if (!com.android.server.accessibility.Flags.enableMagnificationMagnifyNavBarAndIme()) {
mMagnifyIme = false;
Expand Down Expand Up @@ -1247,6 +1272,7 @@ public void onAppTransitionFinishedLocked(IBinder token) {
private final ScreenRecordingCallbackController mScreenRecordingCallbackController;

private volatile boolean mDisableSecureWindows = false;
private volatile boolean mForceScreenshotSecureWindows = false;

/** Creates an instance of the WindowManagerService for the system server. */
public static WindowManagerService main(@NonNull final Context context,
Expand Down Expand Up @@ -10669,10 +10695,17 @@ ScreenCaptureInternal.LayerCaptureArgs getCaptureArgs(
}
}

return new ScreenCaptureInternal.LayerCaptureArgs.Builder(
ScreenCaptureInternal.LayerCaptureArgs.Builder builder =
new ScreenCaptureInternal.LayerCaptureArgs.Builder(
displaySurfaceControl, captureArgs)
.setSourceCrop(mTmpRect)
.build();
.setSourceCrop(mTmpRect);

if (mForceScreenshotSecureWindows) {
builder = builder.setSecureContentPolicy(
SECURE_CONTENT_POLICY_CAPTURE);
}

return builder.build();
}

@Override
Expand Down Expand Up @@ -10870,6 +10903,10 @@ boolean getDisableSecureWindows() {
return mDisableSecureWindows;
}

boolean getForceScreenshotSecureWindows() {
return mForceScreenshotSecureWindows;
}

/**
* Called to notify WMS that the specified window has become visible. This shows a Toast if the
* window is deemed to hold sensitive content.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
import android.app.IApplicationThread;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.ContentResolver;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
Expand Down Expand Up @@ -121,6 +122,7 @@
import android.window.ClientWindowFrames;
import android.window.ConfigurationChangeSetting;
import android.window.InputTransferToken;
import android.window.ScreenCapture;
import android.window.ScreenCaptureInternal;
import android.window.WindowContainerToken;

Expand Down Expand Up @@ -1364,6 +1366,30 @@ public void testCaptureDisplay() {
assertEquals(validRect, resultingArgs.mSourceCrop);
}

@Test
public void testCaptureArgs_forceScreenshotSecureWindows() {
Rect displayBounds = new Rect(0, 0, 100, 200);
spyOn(mDisplayContent);
when(mDisplayContent.getBounds()).thenReturn(displayBounds);
ContentResolver cr = useFakeSettingsProvider();

// secureContentPolicy should be REDACT (default) when setting is disabled
Settings.Secure.putInt(cr, Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS, 0);
mWm.mSettingsObserver.onChange(false,
Settings.Secure.getUriFor(Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS));
ScreenCaptureInternal.LayerCaptureArgs resultingArgs =
mWm.getCaptureArgs(DEFAULT_DISPLAY, null);
assertEquals(ScreenCapture.ScreenCaptureParams.SECURE_CONTENT_POLICY_REDACT,
resultingArgs.mSecureContentPolicy);

// secureContentPolicy should be CAPTURE when setting is enabled
Settings.Secure.putInt(cr, Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS, 1);
mWm.mSettingsObserver.onChange(false,
Settings.Secure.getUriFor(Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS));
resultingArgs = mWm.getCaptureArgs(DEFAULT_DISPLAY, null);
assertEquals(ScreenCapture.ScreenCaptureParams.SECURE_CONTENT_POLICY_CAPTURE,
resultingArgs.mSecureContentPolicy);
}
@Test
public void testGrantInputChannel_sanitizeSpyWindowForApplications() {
final Session session = mock(Session.class);
Expand Down