diff options
| -rw-r--r-- | core/java/android/view/View.java | 106 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 34 |
2 files changed, 139 insertions, 1 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 596c52dcfdf6..4df95bf31c3f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -36,6 +36,7 @@ import static android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY; import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API; import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout; +import static android.view.flags.Flags.sensitiveContentAppProtection; import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision; import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; import static android.view.flags.Flags.viewVelocityApi; @@ -135,6 +136,7 @@ import android.service.credentials.CredentialProviderService; import android.sysprop.DisplayProperties; import android.text.InputType; import android.text.TextUtils; +import android.util.ArraySet; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.FloatProperty; @@ -3701,6 +3703,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * 1 PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT * 1 PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT * 11 PFLAG4_CONTENT_SENSITIVITY_MASK + * 1 PFLAG4_IS_COUNTED_AS_SENSITIVE * |-------|-------|-------|-------| */ @@ -3826,6 +3829,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static final int PFLAG4_CONTENT_SENSITIVITY_MASK = (CONTENT_SENSITIVITY_AUTO | CONTENT_SENSITIVITY_SENSITIVE | CONTENT_SENSITIVITY_NOT_SENSITIVE) << PFLAG4_CONTENT_SENSITIVITY_SHIFT; + + /** + * Whether this view has been counted as a sensitive view or not. + * + * @see AttachInfo#mSensitiveViewsCount + */ + private static final int PFLAG4_IS_COUNTED_AS_SENSITIVE = 0x4000000; /* End of masks for mPrivateFlags4 */ /** @hide */ @@ -10387,6 +10397,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags4 &= ~PFLAG4_CONTENT_SENSITIVITY_MASK; mPrivateFlags4 |= ((mode << PFLAG4_CONTENT_SENSITIVITY_SHIFT) & PFLAG4_CONTENT_SENSITIVITY_MASK); + if (sensitiveContentAppProtection()) { + updateSensitiveViewsCountIfNeeded(isAggregatedVisible()); + } } /** @@ -10418,13 +10431,44 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) public final boolean isContentSensitive() { - if (getContentSensitivity() == CONTENT_SENSITIVITY_SENSITIVE) { + final int contentSensitivity = getContentSensitivity(); + if (contentSensitivity == CONTENT_SENSITIVITY_SENSITIVE) { return true; + } else if (contentSensitivity == CONTENT_SENSITIVITY_NOT_SENSITIVE) { + return false; + } else if (sensitiveContentAppProtection()) { + return SensitiveAutofillHintsHelper + .containsSensitiveAutofillHint(getAutofillHints()); } return false; } /** + * Helper used to track sensitive views when they are added or removed from the window + * based on whether it's laid out and visible. + * + * <p>This method is called from many places (visibility changed, view laid out, view attached + * or detached to/from window, etc...) + */ + private void updateSensitiveViewsCountIfNeeded(boolean appeared) { + if (!sensitiveContentAppProtection() || mAttachInfo == null) { + return; + } + + if (appeared && isContentSensitive()) { + if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) == 0) { + mPrivateFlags4 |= PFLAG4_IS_COUNTED_AS_SENSITIVE; + mAttachInfo.increaseSensitiveViewsCount(); + } + } else { + if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) != 0) { + mPrivateFlags4 &= ~PFLAG4_IS_COUNTED_AS_SENSITIVE; + mAttachInfo.decreaseSensitiveViewsCount(); + } + } + } + + /** * Gets the mode for determining whether this view is important for content capture. * * <p>See {@link #setImportantForContentCapture(int)} and @@ -13457,6 +13501,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } else { mAutofillHints = autofillHints; } + if (sensitiveContentAppProtection()) { + if (getContentSensitivity() == CONTENT_SENSITIVITY_AUTO) { + updateSensitiveViewsCountIfNeeded(isAggregatedVisible()); + } + } } /** @@ -16681,6 +16730,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); + updateSensitiveViewsCountIfNeeded(isVisible); if (!getSystemGestureExclusionRects().isEmpty()) { postUpdate(this::updateSystemGestureExclusionRects); @@ -22670,6 +22720,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); + updateSensitiveViewsCountIfNeeded(false); mAttachInfo = null; if (mOverlay != null) { @@ -31817,6 +31868,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, ScrollCaptureInternal mScrollCaptureInternal; /** + * sensitive views attached to the window + */ + int mSensitiveViewsCount; + + /** * Creates a new set of attachment information with the specified * events handler and thread. * @@ -31835,6 +31891,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mTreeObserver = new ViewTreeObserver(context); } + void increaseSensitiveViewsCount() { + if (mSensitiveViewsCount == 0) { + mViewRootImpl.notifySensitiveContentAppProtection(true); + } + mSensitiveViewsCount++; + } + + void decreaseSensitiveViewsCount() { + mSensitiveViewsCount--; + if (mSensitiveViewsCount == 0) { + mViewRootImpl.notifySensitiveContentAppProtection(false); + } + if (mSensitiveViewsCount < 0) { + Log.wtf(VIEW_LOG_TAG, "mSensitiveViewsCount is negative" + mSensitiveViewsCount); + mSensitiveViewsCount = 0; + } + } + @Nullable ContentCaptureManager getContentCaptureManager(@NonNull Context context) { if (mContentCaptureManager != null) { @@ -32448,6 +32522,36 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } + private static class SensitiveAutofillHintsHelper { + /** + * List of autofill hints deemed sensitive for screen protection during screen share. + */ + private static final ArraySet<String> SENSITIVE_CONTENT_AUTOFILL_HINTS = new ArraySet<>(); + static { + SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_USERNAME); + SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD_AUTO); + SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD); + } + + /** + * Whether View's autofill hints contains a sensitive autofill hint. + * + * @see #SENSITIVE_CONTENT_AUTOFILL_HINTS + */ + static boolean containsSensitiveAutofillHint(@Nullable String[] autofillHints) { + if (autofillHints == null) { + return false; + } + + int size = autofillHints.length; + for (int i = 0; i < size; i++) { + if (SENSITIVE_CONTENT_AUTOFILL_HINTS.contains(autofillHints[i])) { + return true; + } + } + return false; + } + } /** * Returns the current scroll capture hint for this view. diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 94260b223dd2..23a7017b6125 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -58,6 +58,7 @@ import static android.view.ViewRootImplProto.WIDTH; import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES; import static android.view.ViewRootImplProto.WIN_FRAME; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; +import static android.view.flags.Flags.sensitiveContentAppProtection; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; @@ -166,6 +167,7 @@ import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; @@ -924,6 +926,8 @@ public final class ViewRootImpl implements ViewParent, private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection; + private final ISensitiveContentProtectionManager mSensitiveContentProtectionService; + static final class SystemUiVisibilityInfo { int globalVisibility; int localValue; @@ -1203,6 +1207,13 @@ public final class ViewRootImpl implements ViewParent, mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context); + if (sensitiveContentAppProtection()) { + mSensitiveContentProtectionService = + ISensitiveContentProtectionManager.Stub.asInterface( + ServiceManager.getService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE)); + } else { + mSensitiveContentProtectionService = null; + } } public static void addFirstDrawHandler(Runnable callback) { @@ -4154,6 +4165,29 @@ public final class ViewRootImpl implements ViewParent, mWmsRequestSyncGroup.add(this, null /* runnable */); } + /** + * Helper used to notify the service to block projection when a sensitive + * view (the view displays sensitive content) is attached to the window. + * The window manager service is also notified to unblock projection when + * no attached view (to the window) displays sensitive content. + * + * <ol> + * <li>It should only notify service to block projection when first sensitive view is + * attached to the window. + * <li>It should only notify service to unblock projection when all sensitive view are + * removed from the window. + * </ol> + */ + void notifySensitiveContentAppProtection(boolean showSensitiveContent) { + try { + // The window would be blocked during screen share if it shows sensitive content. + mSensitiveContentProtectionService.setSensitiveContentProtection( + getWindowToken(), mContext.getPackageName(), showSensitiveContent); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to protect sensitive content during screen share", ex); + } + } + private void notifyContentCaptureEvents() { if (!isContentCaptureEnabled()) { if (DEBUG_CONTENT_CAPTURE) { |