Merge "Refactor Geocoder Provider System APIs" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 2846221..b89a51a 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -32,6 +32,7 @@
":android.credentials.flags-aconfig-java{.generated_srcjars}",
":android.database.sqlite-aconfig-java{.generated_srcjars}",
":android.hardware.biometrics.flags-aconfig-java{.generated_srcjars}",
+ ":android.hardware.devicestate.feature.flags-aconfig-java{.generated_srcjars}",
":android.hardware.flags-aconfig-java{.generated_srcjars}",
":android.hardware.radio.flags-aconfig-java{.generated_srcjars}",
":android.hardware.usb.flags-aconfig-java{.generated_srcjars}",
@@ -108,6 +109,7 @@
"android.credentials.flags-aconfig",
"android.database.sqlite-aconfig",
"android.hardware.biometrics.flags-aconfig",
+ "android.hardware.devicestate.feature.flags-aconfig",
"android.hardware.flags-aconfig",
"android.hardware.radio.flags-aconfig",
"android.hardware.usb.flags-aconfig",
@@ -227,6 +229,19 @@
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+// DeviceStateManager
+aconfig_declarations {
+ name: "android.hardware.devicestate.feature.flags-aconfig",
+ package: "android.hardware.devicestate.feature.flags",
+ srcs: ["core/java/android/hardware/devicestate/feature/*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.hardware.devicestate.feature.flags-aconfig-java",
+ aconfig_declarations: "android.hardware.devicestate.feature.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
// Input
aconfig_declarations {
name: "com.android.hardware.input.input-aconfig",
diff --git a/Android.bp b/Android.bp
index e12f74f..870df5a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -508,6 +508,8 @@
lint: {
baseline_filename: "lint-baseline.xml",
},
+ // For jarjar repackaging
+ jarjar_prefix: "com.android.internal.hidden_from_bootclasspath",
}
java_library {
diff --git a/core/api/current.txt b/core/api/current.txt
index ec8699a..5aa10e9 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -144,10 +144,12 @@
field public static final String MANAGE_DEVICE_POLICY_AUDIO_OUTPUT = "android.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT";
field public static final String MANAGE_DEVICE_POLICY_AUTOFILL = "android.permission.MANAGE_DEVICE_POLICY_AUTOFILL";
field public static final String MANAGE_DEVICE_POLICY_BACKUP_SERVICE = "android.permission.MANAGE_DEVICE_POLICY_BACKUP_SERVICE";
+ field @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled") public static final String MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL = "android.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL";
field public static final String MANAGE_DEVICE_POLICY_BLUETOOTH = "android.permission.MANAGE_DEVICE_POLICY_BLUETOOTH";
field public static final String MANAGE_DEVICE_POLICY_BUGREPORT = "android.permission.MANAGE_DEVICE_POLICY_BUGREPORT";
field public static final String MANAGE_DEVICE_POLICY_CALLS = "android.permission.MANAGE_DEVICE_POLICY_CALLS";
field public static final String MANAGE_DEVICE_POLICY_CAMERA = "android.permission.MANAGE_DEVICE_POLICY_CAMERA";
+ field @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled") public static final String MANAGE_DEVICE_POLICY_CAMERA_TOGGLE = "android.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE";
field public static final String MANAGE_DEVICE_POLICY_CERTIFICATES = "android.permission.MANAGE_DEVICE_POLICY_CERTIFICATES";
field public static final String MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE = "android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE";
field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final String MANAGE_DEVICE_POLICY_CONTENT_PROTECTION = "android.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION";
@@ -169,6 +171,7 @@
field @FlaggedApi("android.app.admin.flags.esim_management_enabled") public static final String MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS = "android.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS";
field public static final String MANAGE_DEVICE_POLICY_METERED_DATA = "android.permission.MANAGE_DEVICE_POLICY_METERED_DATA";
field public static final String MANAGE_DEVICE_POLICY_MICROPHONE = "android.permission.MANAGE_DEVICE_POLICY_MICROPHONE";
+ field @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled") public static final String MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE = "android.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE";
field public static final String MANAGE_DEVICE_POLICY_MOBILE_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK";
field public static final String MANAGE_DEVICE_POLICY_MODIFY_USERS = "android.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS";
field public static final String MANAGE_DEVICE_POLICY_MTE = "android.permission.MANAGE_DEVICE_POLICY_MTE";
@@ -454,6 +457,7 @@
field public static final int allowBackup = 16843392; // 0x1010280
field public static final int allowClearUserData = 16842757; // 0x1010005
field public static final int allowClickWhenDisabled = 16844312; // 0x1010618
+ field @FlaggedApi("android.security.asm_restrictions_enabled") public static final int allowCrossUidActivitySwitchFromBelow;
field public static final int allowEmbedded = 16843765; // 0x10103f5
field public static final int allowGameAngleDriver = 16844376; // 0x1010658
field public static final int allowGameDownscaling = 16844377; // 0x1010659
@@ -687,6 +691,7 @@
field public static final int defaultHeight = 16844021; // 0x10104f5
field @FlaggedApi("android.content.res.default_locale") public static final int defaultLocale;
field public static final int defaultToDeviceProtectedStorage = 16844036; // 0x1010504
+ field @FlaggedApi("android.nfc.Flags.FLAG_OBSERVE_MODE") public static final int defaultToObserveMode;
field public static final int defaultValue = 16843245; // 0x10101ed
field public static final int defaultWidth = 16844020; // 0x10104f4
field public static final int delay = 16843212; // 0x10101cc
@@ -1491,6 +1496,7 @@
field @Deprecated public static final int sharedUserLabel = 16843361; // 0x1010261
field public static final int sharedUserMaxSdkVersion = 16844365; // 0x101064d
field public static final int shell = 16844180; // 0x1010594
+ field @FlaggedApi("com.android.text.flags.use_bounds_for_width") public static final int shiftDrawingOffsetForStartOverhang;
field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
field public static final int shortcutId = 16844072; // 0x1010528
field public static final int shortcutLongLabel = 16844074; // 0x101052a
@@ -5459,11 +5465,15 @@
method public int getDeferralPolicy();
method @Nullable public String getDeliveryGroupMatchingKey();
method public int getDeliveryGroupPolicy();
+ method @FlaggedApi("android.app.bcast_event_timestamps") public long getEventTriggerTimestampMillis();
+ method @FlaggedApi("android.app.bcast_event_timestamps") public long getRemoteEventTriggerTimestampMillis();
method public boolean isShareIdentityEnabled();
method @NonNull public static android.app.BroadcastOptions makeBasic();
method @NonNull public android.app.BroadcastOptions setDeferralPolicy(int);
method @NonNull public android.app.BroadcastOptions setDeliveryGroupMatchingKey(@NonNull String, @NonNull String);
method @NonNull public android.app.BroadcastOptions setDeliveryGroupPolicy(int);
+ method @FlaggedApi("android.app.bcast_event_timestamps") public void setEventTriggerTimestampMillis(long);
+ method @FlaggedApi("android.app.bcast_event_timestamps") public void setRemoteEventTriggerTimestampMillis(long);
method @NonNull public android.app.BroadcastOptions setShareIdentityEnabled(boolean);
method @NonNull public android.os.Bundle toBundle();
field public static final int DEFERRAL_POLICY_DEFAULT = 0; // 0x0
@@ -8113,6 +8123,7 @@
method public boolean isLogoutEnabled();
method public boolean isManagedProfile(@NonNull android.content.ComponentName);
method public boolean isMasterVolumeMuted(@NonNull android.content.ComponentName);
+ method @FlaggedApi("android.app.admin.flags.is_mte_policy_enforced") public static boolean isMtePolicyEnforced();
method public boolean isNetworkLoggingEnabled(@Nullable android.content.ComponentName);
method public boolean isOrganizationOwnedDeviceWithManagedProfile();
method public boolean isOverrideApnEnabled(@NonNull android.content.ComponentName);
@@ -20002,11 +20013,14 @@
public final class ExtensionSessionConfiguration {
ctor public ExtensionSessionConfiguration(int, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.StateCallback);
+ method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void clearColorSpace();
+ method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") @Nullable public android.graphics.ColorSpace getColorSpace();
method @NonNull public java.util.concurrent.Executor getExecutor();
method public int getExtension();
method @NonNull public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations();
method @Nullable public android.hardware.camera2.params.OutputConfiguration getPostviewOutputConfiguration();
method @NonNull public android.hardware.camera2.CameraExtensionSession.StateCallback getStateCallback();
+ method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setColorSpace(@NonNull android.graphics.ColorSpace.Named);
method public void setPostviewOutputConfiguration(@Nullable android.hardware.camera2.params.OutputConfiguration);
}
@@ -22731,7 +22745,6 @@
public final class MediaCodec.QueueRequest {
method public void queue();
- method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setBufferInfos(@NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
method @NonNull public android.media.MediaCodec.QueueRequest setEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @NonNull android.media.MediaCodec.CryptoInfo);
method @NonNull public android.media.MediaCodec.QueueRequest setFlags(int);
@@ -22741,6 +22754,7 @@
method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int);
method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);
method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setMultiFrameEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>, @NonNull java.util.ArrayDeque<android.media.MediaCodec.CryptoInfo>);
+ method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setMultiFrameLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
method @NonNull public android.media.MediaCodec.QueueRequest setPresentationTimeUs(long);
method @NonNull public android.media.MediaCodec.QueueRequest setStringParameter(@NonNull String, @NonNull String);
}
@@ -22749,12 +22763,16 @@
method @NonNull public String getCanonicalName();
method public android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(String);
method @NonNull public String getName();
+ method @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public int getSecurityModel();
method public String[] getSupportedTypes();
method public boolean isAlias();
method public boolean isEncoder();
method public boolean isHardwareAccelerated();
method public boolean isSoftwareOnly();
method public boolean isVendor();
+ field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_MEMORY_SAFE = 1; // 0x1
+ field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_SANDBOXED = 0; // 0x0
+ field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 2; // 0x2
}
public static final class MediaCodecInfo.AudioCapabilities {
@@ -23583,6 +23601,9 @@
field public static final int COLOR_TRANSFER_LINEAR = 1; // 0x1
field public static final int COLOR_TRANSFER_SDR_VIDEO = 3; // 0x3
field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6
+ field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_MEMORY_SAFE = 2; // 0x2
+ field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_SANDBOXED = 1; // 0x1
+ field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 4; // 0x4
field public static final String KEY_AAC_DRC_ALBUM_MODE = "aac-drc-album-mode";
field public static final String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
field public static final String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
@@ -23664,6 +23685,7 @@
field public static final String KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
field public static final String KEY_ROTATION = "rotation-degrees";
field public static final String KEY_SAMPLE_RATE = "sample-rate";
+ field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final String KEY_SECURITY_MODEL = "security-model";
field public static final String KEY_SLICE_HEIGHT = "slice-height";
field public static final String KEY_SLOW_MOTION_MARKERS = "slow-motion-markers";
field public static final String KEY_STRIDE = "stride";
@@ -42390,6 +42412,7 @@
field public static final int SUPPORTS_SET_INACTIVE = 2; // 0x2
field public static final int SUPPORTS_STREAM = 4; // 0x4
field public static final int SUPPORTS_TRANSFER = 8; // 0x8
+ field @FlaggedApi("com.android.server.telecom.flags.transactional_video_state") public static final int SUPPORTS_VIDEO_CALLING = 16; // 0x10
field public static final int VIDEO_CALL = 2; // 0x2
}
@@ -42425,6 +42448,7 @@
method @NonNull public android.os.ParcelUuid getCallId();
method public void requestCallEndpointChange(@NonNull android.telecom.CallEndpoint, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
method @FlaggedApi("com.android.server.telecom.flags.set_mute_state") public void requestMuteState(boolean, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
+ method @FlaggedApi("com.android.server.telecom.flags.transactional_video_state") public void requestVideoState(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
method public void sendEvent(@NonNull String, @NonNull android.os.Bundle);
method public void setActive(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
method public void setInactive(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
@@ -42473,6 +42497,7 @@
method public void onCallStreamingFailed(int);
method public void onEvent(@NonNull String, @NonNull android.os.Bundle);
method public void onMuteStateChanged(boolean);
+ method @FlaggedApi("com.android.server.telecom.flags.transactional_video_state") public default void onVideoStateChanged(int);
}
public final class CallException extends java.lang.RuntimeException implements android.os.Parcelable {
@@ -47526,6 +47551,7 @@
method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.text.DynamicLayout.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
method @NonNull public android.text.DynamicLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float);
method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") @NonNull public android.text.DynamicLayout.Builder setMinimumFontMetrics(@Nullable android.graphics.Paint.FontMetrics);
+ method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.DynamicLayout.Builder setShiftDrawingOffsetForStartOverhang(boolean);
method @NonNull public android.text.DynamicLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.DynamicLayout.Builder setUseBoundsForWidth(boolean);
method @NonNull public android.text.DynamicLayout.Builder setUseLineSpacingFromFallbacks(boolean);
@@ -47729,6 +47755,7 @@
method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @Nullable public final int[] getRightIndents();
method public float getSecondaryHorizontal(int);
method public void getSelectionPath(int, int, android.graphics.Path);
+ method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public boolean getShiftDrawingOffsetForStartOverhang();
method public final float getSpacingAdd();
method public final float getSpacingMultiplier();
method @NonNull public final CharSequence getText();
@@ -47785,6 +47812,7 @@
method @NonNull public android.text.Layout.Builder setMaxLines(@IntRange(from=1) int);
method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") @NonNull public android.text.Layout.Builder setMinimumFontMetrics(@Nullable android.graphics.Paint.FontMetrics);
method @NonNull public android.text.Layout.Builder setRightIndents(@Nullable int[]);
+ method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.Layout.Builder setShiftDrawingOffsetForStartOverhang(boolean);
method @NonNull public android.text.Layout.Builder setTextDirectionHeuristic(@NonNull android.text.TextDirectionHeuristic);
method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.Layout.Builder setUseBoundsForWidth(boolean);
}
@@ -48056,6 +48084,7 @@
method @NonNull public android.text.StaticLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float);
method @NonNull public android.text.StaticLayout.Builder setMaxLines(@IntRange(from=0) int);
method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") @NonNull public android.text.StaticLayout.Builder setMinimumFontMetrics(@Nullable android.graphics.Paint.FontMetrics);
+ method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.StaticLayout.Builder setShiftDrawingOffsetForStartOverhang(boolean);
method public android.text.StaticLayout.Builder setText(CharSequence);
method @NonNull public android.text.StaticLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.StaticLayout.Builder setUseBoundsForWidth(boolean);
@@ -50565,7 +50594,6 @@
method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
method public default void setChildBoundingInsets(@NonNull android.graphics.Rect);
method public default void setTouchableRegion(@Nullable android.graphics.Region);
- method @FlaggedApi("com.android.window.flags.transfer_gesture_to_embedded") public default boolean transferHostTouchGestureToEmbedded(@NonNull android.view.SurfaceControlViewHost.SurfacePackage);
}
@UiThread public static interface AttachedSurfaceControl.OnBufferTransformHintChangedListener {
@@ -52283,6 +52311,7 @@
public static final class SurfaceControlViewHost.SurfacePackage implements android.os.Parcelable {
ctor public SurfaceControlViewHost.SurfacePackage(@NonNull android.view.SurfaceControlViewHost.SurfacePackage);
method public int describeContents();
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @Nullable public android.window.InputTransferToken getInputTransferToken();
method @NonNull public android.view.SurfaceControl getSurfaceControl();
method public void notifyConfigurationChanged(@NonNull android.content.res.Configuration);
method public void notifyDetachedFromWindow();
@@ -53243,7 +53272,7 @@
field protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
field protected static final int[] PRESSED_STATE_SET;
field protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET;
- field @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = 0.0f;
+ field @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = (0.0f/0.0f);
field @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public static final float REQUESTED_FRAME_RATE_CATEGORY_HIGH = -4.0f;
field @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public static final float REQUESTED_FRAME_RATE_CATEGORY_LOW = -2.0f;
field @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public static final float REQUESTED_FRAME_RATE_CATEGORY_NORMAL = -3.0f;
@@ -54425,8 +54454,10 @@
method public default void removeProposedRotationListener(@NonNull java.util.function.IntConsumer);
method @FlaggedApi("com.android.window.flags.screen_recording_callbacks") @RequiresPermission(android.Manifest.permission.DETECT_SCREEN_RECORDING) public default void removeScreenRecordingCallback(@NonNull java.util.function.Consumer<java.lang.Integer>);
method public void removeViewImmediate(android.view.View);
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default boolean transferTouchGesture(@NonNull android.window.InputTransferToken, @NonNull android.window.InputTransferToken);
method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void unregisterSurfaceControlInputReceiver(@NonNull android.view.SurfaceControl);
method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void unregisterTrustedPresentationListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
+ field @FlaggedApi("com.android.window.flags.cover_display_opt_in") public static final int COMPAT_SMALL_COVER_SCREEN_OPT_IN = 1; // 0x1
field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
field @FlaggedApi("com.android.window.flags.untrusted_embedding_state_sharing") public static final String PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING = "android.window.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING";
@@ -54439,6 +54470,7 @@
field public static final String PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE";
field @FlaggedApi("com.android.window.flags.app_compat_properties_api") public static final String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES";
field public static final String PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS = "android.window.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS";
+ field @FlaggedApi("com.android.window.flags.cover_display_opt_in") public static final String PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN = "android.window.PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN";
field @FlaggedApi("com.android.window.flags.app_compat_properties_api") public static final String PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE";
field @FlaggedApi("com.android.window.flags.app_compat_properties_api") public static final String PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE";
field public static final String PROPERTY_COMPAT_ENABLE_FAKE_FOCUS = "android.window.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS";
@@ -60872,6 +60904,7 @@
method public float getShadowDx();
method public float getShadowDy();
method public float getShadowRadius();
+ method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public boolean getShiftDrawingOffsetForStartOverhang();
method public final boolean getShowSoftInputOnFocus();
method public CharSequence getText();
method @NonNull public android.view.textclassifier.TextClassifier getTextClassifier();
@@ -61008,6 +61041,7 @@
method public void setSearchResultHighlights(@Nullable int...);
method public void setSelectAllOnFocus(boolean);
method public void setShadowLayer(float, float, float, int);
+ method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public void setShiftDrawingOffsetForStartOverhang(boolean);
method public final void setShowSoftInputOnFocus(boolean);
method public void setSingleLine();
method public void setSingleLine(boolean);
diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt
index 9b8ab9b..1b0da05 100644
--- a/core/api/lint-baseline.txt
+++ b/core/api/lint-baseline.txt
@@ -1461,6 +1461,7 @@
New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getItalicOverride(int)
UnflaggedApi: android.graphics.text.PositionedGlyphs#getWeightOverride(int):
New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getWeightOverride(int)
+
UnflaggedApi: android.hardware.camera2.ExtensionCaptureRequest:
New API must be flagged with @FlaggedApi: class android.hardware.camera2.ExtensionCaptureRequest
UnflaggedApi: android.hardware.camera2.ExtensionCaptureRequest#ExtensionCaptureRequest():
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 20a621ba..8fe3876 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -195,6 +195,7 @@
field public static final String MANAGE_DEFAULT_APPLICATIONS = "android.permission.MANAGE_DEFAULT_APPLICATIONS";
field public static final String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
field public static final String MANAGE_DEVICE_POLICY_APP_EXEMPTIONS = "android.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS";
+ field @FlaggedApi("android.app.admin.flags.device_theft_api_enabled") public static final String MANAGE_DEVICE_POLICY_THEFT_DETECTION = "android.permission.MANAGE_DEVICE_POLICY_THEFT_DETECTION";
field @FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled") public static final String MANAGE_ENHANCED_CONFIRMATION_STATES = "android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES";
field public static final String MANAGE_ETHERNET_NETWORKS = "android.permission.MANAGE_ETHERNET_NETWORKS";
field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
@@ -203,7 +204,6 @@
field public static final String MANAGE_HOTWORD_DETECTION = "android.permission.MANAGE_HOTWORD_DETECTION";
field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
field public static final String MANAGE_LOW_POWER_STANDBY = "android.permission.MANAGE_LOW_POWER_STANDBY";
- field @FlaggedApi("com.android.media.flags.limit_manage_media_projection") public static final String MANAGE_MEDIA_PROJECTION = "android.permission.MANAGE_MEDIA_PROJECTION";
field public static final String MANAGE_MUSIC_RECOGNITION = "android.permission.MANAGE_MUSIC_RECOGNITION";
field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
field public static final String MANAGE_ONE_TIME_PERMISSION_SESSIONS = "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS";
@@ -594,6 +594,7 @@
field public static final int FOREGROUND_SERVICE_API_TYPE_MICROPHONE = 6; // 0x6
field public static final int FOREGROUND_SERVICE_API_TYPE_PHONE_CALL = 7; // 0x7
field public static final int FOREGROUND_SERVICE_API_TYPE_USB = 8; // 0x8
+ field @FlaggedApi("android.media.audio.foreground_audio_control") public static final int PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL = 64; // 0x40
field public static final int PROCESS_CAPABILITY_FOREGROUND_CAMERA = 2; // 0x2
field public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1; // 0x1
field public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 4; // 0x4
@@ -1322,6 +1323,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean isDpcDownloaded();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isManagedKiosk();
method public boolean isSecondaryLockscreenEnabled(@NonNull android.os.UserHandle);
+ method @FlaggedApi("android.app.admin.flags.device_theft_api_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_THEFT_DETECTION) public boolean isTheftDetectionTriggered();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isUnattendedManagedKiosk();
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
@@ -4756,9 +4758,13 @@
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public final class CameraOutputSurface {
ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public CameraOutputSurface(@NonNull android.view.Surface, @NonNull android.util.Size);
+ method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public int getColorSpace();
+ method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public long getDynamicRangeProfile();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public int getImageFormat();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.util.Size getSize();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.view.Surface getSurface();
+ method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setColorSpace(int);
+ method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setDynamicRangeProfile(long);
}
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public class CharacteristicsMap {
@@ -4835,6 +4841,39 @@
}
+package android.hardware.devicestate {
+
+ @FlaggedApi("android.hardware.devicestate.feature.flags.device_state_property_api") public final class DeviceState {
+ method @IntRange(from=0x0) public int getIdentifier();
+ method @NonNull public String getName();
+ method public boolean hasProperties(@NonNull int...);
+ method public boolean hasProperty(int);
+ field public static final int PROPERTY_EMULATED_ONLY = 10; // 0xa
+ field public static final int PROPERTY_EXTENDED_DEVICE_STATE_EXTERNAL_DISPLAY = 15; // 0xf
+ field public static final int PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT = 17; // 0x11
+ field public static final int PROPERTY_FEATURE_REAR_DISPLAY = 16; // 0x10
+ field public static final int PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY = 12; // 0xc
+ field public static final int PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY = 11; // 0xb
+ field public static final int PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED = 1; // 0x1
+ field public static final int PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN = 2; // 0x2
+ field public static final int PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN = 3; // 0x3
+ field public static final int PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP = 13; // 0xd
+ field public static final int PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE = 14; // 0xe
+ }
+
+ @FlaggedApi("android.hardware.devicestate.feature.flags.device_state_property_api") public final class DeviceStateManager {
+ method @NonNull public java.util.List<android.hardware.devicestate.DeviceState> getSupportedDeviceStates();
+ method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
+ method public void unregisterCallback(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
+ }
+
+ public static interface DeviceStateManager.DeviceStateCallback {
+ method public default void onDeviceStateChanged(@NonNull android.hardware.devicestate.DeviceState);
+ method public default void onSupportedStatesChanged(@NonNull java.util.List<android.hardware.devicestate.DeviceState>);
+ }
+
+}
+
package android.hardware.display {
public final class AmbientBrightnessDayStats implements android.os.Parcelable {
@@ -10239,6 +10278,7 @@
ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public ApduServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo, boolean) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilter(@NonNull String);
method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilterToAutoTransact(@NonNull String);
+ method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean defaultToObserveMode();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dumpDebug(@NonNull android.util.proto.ProtoOutputStream);
@@ -10268,6 +10308,7 @@
method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresUnlock();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void resetOffHostSecureElement();
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setCategoryOtherServiceEnabled(boolean);
+ method @FlaggedApi("android.nfc.nfc_observe_mode") public void setDefaultToObserveMode(boolean);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOffHostSecureElement(@NonNull String);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -14351,9 +14392,9 @@
@FlaggedApi("com.android.internal.telephony.flags.use_oem_domain_selection_service") public abstract class DomainSelectionService extends android.app.Service {
ctor public DomainSelectionService();
+ method @NonNull public java.util.concurrent.Executor getCreateExecutor();
method public void onBarringInfoUpdated(int, int, @NonNull android.telephony.BarringInfo);
method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method @NonNull public java.util.concurrent.Executor onCreateExecutor();
method public abstract void onDomainSelection(@NonNull android.telephony.DomainSelectionService.SelectionAttributes, @NonNull android.telephony.TransportSelectorCallback);
method public void onServiceStateUpdated(int, int, @NonNull android.telephony.ServiceState);
field public static final int SCAN_TYPE_FULL_SERVICE = 2; // 0x2
@@ -15133,6 +15174,7 @@
method @Deprecated public boolean getDataEnabled(int);
method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getDefaultRespondViaMessageApplication();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion(int);
+ method @FlaggedApi("android.permission.flags.get_emergency_role_holder_api_enabled") @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getEmergencyAssistancePackage();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index a6505c8..ca9fab8 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -535,6 +535,10 @@
Listeners should always be at end of argument list (method `stopSatelliteTransmissionUpdates`)
+MethodNameUnits: android.hardware.camera2.extension.CameraOutputSurface#getColorSpace():
+ Expected method name units to be `Bytes`, was `Space` in `getColorSpace`
+
+
MissingGetterMatchingBuilder: android.service.voice.HotwordTrainingData.Builder#addTrainingAudio(android.service.voice.HotwordTrainingAudio):
android.service.voice.HotwordTrainingData does not declare a `getTrainingAudios()` method matching method android.service.voice.HotwordTrainingData.Builder.addTrainingAudio(android.service.voice.HotwordTrainingAudio)
MissingGetterMatchingBuilder: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallViaAudioProcessing(boolean):
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f6366a2..334d9e6 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1620,22 +1620,26 @@
package android.hardware.devicestate {
- public final class DeviceStateManager {
+ @FlaggedApi("android.hardware.devicestate.feature.flags.device_state_property_api") public final class DeviceState {
+ ctor @Deprecated public DeviceState(@IntRange(from=android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE_IDENTIFIER, to=android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE_IDENTIFIER) int, @NonNull String, int);
+ ctor public DeviceState(@IntRange(from=android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE_IDENTIFIER, to=android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE_IDENTIFIER) int, @NonNull String, @NonNull java.util.Set<java.lang.Integer>);
+ field public static final int PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST = 8; // 0x8
+ }
+
+ @FlaggedApi("android.hardware.devicestate.feature.flags.device_state_property_api") public final class DeviceStateManager {
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void cancelBaseStateOverride();
method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) public void cancelStateRequest();
- method @NonNull public int[] getSupportedStates();
- method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
+ method @Deprecated @NonNull public int[] getSupportedStates();
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void requestBaseStateOverride(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
- method public void unregisterCallback(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
- field public static final int MAXIMUM_DEVICE_STATE = 255; // 0xff
- field public static final int MINIMUM_DEVICE_STATE = 0; // 0x0
+ field public static final int MAXIMUM_DEVICE_STATE_IDENTIFIER = 10000; // 0x2710
+ field public static final int MINIMUM_DEVICE_STATE_IDENTIFIER = 0; // 0x0
}
public static interface DeviceStateManager.DeviceStateCallback {
- method public default void onBaseStateChanged(int);
- method public void onStateChanged(int);
- method public default void onSupportedStatesChanged(@NonNull int[]);
+ method @Deprecated public default void onBaseStateChanged(int);
+ method @Deprecated public void onStateChanged(int);
+ method @Deprecated public default void onSupportedStatesChanged(@NonNull int[]);
}
public final class DeviceStateRequest {
diff --git a/core/java/android/adaptiveauth/flags.aconfig b/core/java/android/adaptiveauth/flags.aconfig
index 39e46bb..de4e607 100644
--- a/core/java/android/adaptiveauth/flags.aconfig
+++ b/core/java/android/adaptiveauth/flags.aconfig
@@ -1,6 +1,13 @@
package: "android.adaptiveauth"
flag {
+ name: "enable_adaptive_auth"
+ namespace: "biometrics"
+ description: "Feature flag for enabling the new adaptive auth service"
+ bug: "285053096"
+}
+
+flag {
name: "report_biometric_auth_attempts"
namespace: "biometrics"
description: "Control the usage of the biometric auth signal in adaptive auth"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a8d183a..237d31c 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -20,6 +20,7 @@
import static android.app.WindowConfiguration.windowingModeToString;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.media.audio.Flags.FLAG_FOREGROUND_AUDIO_CONTROL;
import android.Manifest;
import android.annotation.ColorInt;
@@ -794,6 +795,7 @@
PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK,
PROCESS_CAPABILITY_BFSL,
PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK,
+ PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProcessCapability {}
@@ -943,6 +945,14 @@
public static final int PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK = 1 << 5;
/**
+ * @hide
+ * Process can access volume APIs and can request audio focus with GAIN.
+ */
+ @FlaggedApi(FLAG_FOREGROUND_AUDIO_CONTROL)
+ @SystemApi
+ public static final int PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL = 1 << 6;
+
+ /**
* @hide all capabilities, the ORing of all flags in {@link ProcessCapability}.
*
* Don't expose it as TestApi -- we may add new capabilities any time, which could
@@ -953,7 +963,8 @@
| PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
| PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
| PROCESS_CAPABILITY_BFSL
- | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
+ | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK
+ | PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
/**
* All implicit capabilities. There are capabilities that process automatically have.
@@ -975,6 +986,7 @@
pw.print((caps & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0 ? 'N' : '-');
pw.print((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-');
pw.print((caps & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0 ? 'U' : '-');
+ pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL) != 0 ? 'A' : '-');
}
/** @hide */
@@ -986,6 +998,7 @@
sb.append((caps & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0 ? 'N' : '-');
sb.append((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-');
sb.append((caps & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0 ? 'U' : '-');
+ sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL) != 0 ? 'A' : '-');
}
/**
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index e14bf68..2a2c5f0 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -20,6 +20,7 @@
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
import static android.view.Display.INVALID_DISPLAY;
@@ -1849,7 +1850,7 @@
public int getPendingIntentLaunchFlags() {
// b/243794108: Ignore all flags except the new task flag, to be reconsidered in b/254490217
return mPendingIntentLaunchFlags &
- (FLAG_ACTIVITY_NEW_TASK | FLAG_RECEIVER_FOREGROUND);
+ (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_RECEIVER_FOREGROUND);
}
/**
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 2100425..409badb 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,7 +16,9 @@
package android.app;
+
import static android.location.flags.Flags.FLAG_LOCATION_BYPASS;
+import static android.media.audio.Flags.foregroundAudioControl;
import static android.permission.flags.Flags.FLAG_OP_ENABLE_MOBILE_DATA_BY_USER;
import static android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED;
import static android.view.contentprotection.flags.Flags.FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED;
@@ -3229,6 +3231,10 @@
* @hide
*/
public static @Mode int opToDefaultMode(int op) {
+ if (op == OP_TAKE_AUDIO_FOCUS && foregroundAudioControl()) {
+ // when removing the flag, change the entry in sAppOpInfos for OP_TAKE_AUDIO_FOCUS
+ return AppOpsManager.MODE_FOREGROUND;
+ }
return sAppOpInfos[op].defaultMode;
}
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index f727ee5..1b5b0fc 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -16,6 +16,8 @@
package android.app;
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -65,6 +67,8 @@
private @Nullable BundleMerger mDeliveryGroupExtrasMerger;
private @Nullable IntentFilter mDeliveryGroupMatchingFilter;
private @DeferralPolicy int mDeferralPolicy;
+ private @CurrentTimeMillisLong long mEventTriggerTimestampMillis;
+ private @CurrentTimeMillisLong long mRemoteEventTriggerTimestampMillis;
/** @hide */
@IntDef(flag = true, prefix = { "FLAG_" }, value = {
@@ -190,6 +194,18 @@
"android:broadcast.idForResponseEvent";
/**
+ * Corresponds to {@link #setEventTriggerTimestampMillis(long)}.
+ */
+ private static final String KEY_EVENT_TRIGGER_TIMESTAMP =
+ "android:broadcast.eventTriggerTimestamp";
+
+ /**
+ * Corresponds to {@link #setRemoteEventTriggerTimestampMillis(long)}.
+ */
+ private static final String KEY_REMOTE_EVENT_TRIGGER_TIMESTAMP =
+ "android:broadcast.remoteEventTriggerTimestamp";
+
+ /**
* Corresponds to {@link #setDeliveryGroupPolicy(int)}.
*/
private static final String KEY_DELIVERY_GROUP_POLICY =
@@ -341,6 +357,8 @@
mRequireNoneOfPermissions = opts.getStringArray(KEY_REQUIRE_NONE_OF_PERMISSIONS);
mRequireCompatChangeId = opts.getLong(KEY_REQUIRE_COMPAT_CHANGE_ID, CHANGE_INVALID);
mIdForResponseEvent = opts.getLong(KEY_ID_FOR_RESPONSE_EVENT);
+ mEventTriggerTimestampMillis = opts.getLong(KEY_EVENT_TRIGGER_TIMESTAMP);
+ mRemoteEventTriggerTimestampMillis = opts.getLong(KEY_REMOTE_EVENT_TRIGGER_TIMESTAMP);
mDeliveryGroupPolicy = opts.getInt(KEY_DELIVERY_GROUP_POLICY,
DELIVERY_GROUP_POLICY_ALL);
mDeliveryGroupMatchingNamespaceFragment = opts.getString(KEY_DELIVERY_GROUP_NAMESPACE);
@@ -787,6 +805,60 @@
}
/**
+ * Set the timestamp for the event that triggered this broadcast, in
+ * {@link System#currentTimeMillis()} timebase.
+ *
+ * <p> For instance, if this broadcast is for a push message, then this timestamp
+ * could correspond to when the device received the message.
+ *
+ * @param timestampMillis the timestamp in {@link System#currentTimeMillis()} timebase that
+ * correspond to the event that triggered this broadcast.
+ */
+ @FlaggedApi(android.app.Flags.FLAG_BCAST_EVENT_TIMESTAMPS)
+ public void setEventTriggerTimestampMillis(@CurrentTimeMillisLong long timestampMillis) {
+ mEventTriggerTimestampMillis = timestampMillis;
+ }
+
+ /**
+ * Return the timestamp for the event that triggered this broadcast, in
+ * {@link System#currentTimeMillis()} timebase.
+ *
+ * @return the timestamp in {@link System#currentTimeMillis()} timebase that was previously
+ * set using {@link #setEventTriggerTimestampMillis(long)}.
+ */
+ @FlaggedApi(android.app.Flags.FLAG_BCAST_EVENT_TIMESTAMPS)
+ public @CurrentTimeMillisLong long getEventTriggerTimestampMillis() {
+ return mEventTriggerTimestampMillis;
+ }
+
+ /**
+ * Set the timestamp for the remote event, if any, that triggered this broadcast, in
+ * {@link System#currentTimeMillis()} timebase.
+ *
+ * <p> For instance, if this broadcast is for a push message, then this timestamp
+ * could correspond to when the message originated remotely.
+ *
+ * @param timestampMillis the timestamp in {@link System#currentTimeMillis()} timebase that
+ * correspond to the remote event that triggered this broadcast.
+ */
+ @FlaggedApi(android.app.Flags.FLAG_BCAST_EVENT_TIMESTAMPS)
+ public void setRemoteEventTriggerTimestampMillis(@CurrentTimeMillisLong long timestampMillis) {
+ mRemoteEventTriggerTimestampMillis = timestampMillis;
+ }
+
+ /**
+ * Return the timestamp for the remote event that triggered this broadcast, in
+ * {@link System#currentTimeMillis()} timebase.
+ *
+ * @return the timestamp in {@link System#currentTimeMillis()} timebase that was previously
+ * set using {@link #setRemoteEventTriggerTimestampMillis(long)}}.
+ */
+ @FlaggedApi(android.app.Flags.FLAG_BCAST_EVENT_TIMESTAMPS)
+ public @CurrentTimeMillisLong long getRemoteEventTriggerTimestampMillis() {
+ return mRemoteEventTriggerTimestampMillis;
+ }
+
+ /**
* Sets deferral policy for this broadcast that specifies how this broadcast
* can be deferred for delivery at some future point.
*/
@@ -1120,6 +1192,12 @@
if (mIdForResponseEvent != 0) {
b.putLong(KEY_ID_FOR_RESPONSE_EVENT, mIdForResponseEvent);
}
+ if (mEventTriggerTimestampMillis > 0) {
+ b.putLong(KEY_EVENT_TRIGGER_TIMESTAMP, mEventTriggerTimestampMillis);
+ }
+ if (mRemoteEventTriggerTimestampMillis > 0) {
+ b.putLong(KEY_REMOTE_EVENT_TRIGGER_TIMESTAMP, mRemoteEventTriggerTimestampMillis);
+ }
if (mDeliveryGroupPolicy != DELIVERY_GROUP_POLICY_ALL) {
b.putInt(KEY_DELIVERY_GROUP_POLICY, mDeliveryGroupPolicy);
}
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index f92ff83..da0cc01 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -31,6 +31,7 @@
per-file SystemServiceRegistry.java = file:/services/core/java/com/android/server/am/OWNERS
per-file *UserSwitchObserver* = file:/services/core/java/com/android/server/am/OWNERS
per-file *UiAutomation* = file:/services/accessibility/OWNERS
+per-file *UiAutomation* = file:/core/java/android/permission/OWNERS
per-file GameManager* = file:/GAME_MANAGER_OWNERS
per-file GameMode* = file:/GAME_MANAGER_OWNERS
per-file GameState* = file:/GAME_MANAGER_OWNERS
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index ff23f09..350b1ed 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -34,3 +34,10 @@
description: "Add a new callback in Service to indicate a FGS has reached its timeout."
bug: "317799821"
}
+
+flag {
+ name: "bcast_event_timestamps"
+ namespace: "backstage_power"
+ description: "Add APIs for clients to provide broadcast event trigger timestamps"
+ bug: "325136414"
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 34fb754..367ade0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -45,6 +45,7 @@
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_STATUS_BAR;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_THEFT_DETECTION;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIFI;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIPE_DATA;
@@ -55,6 +56,7 @@
import static android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED;
import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED;
import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
+import static android.app.admin.flags.Flags.FLAG_IS_MTE_POLICY_ENFORCED;
import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
@@ -153,6 +155,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.org.conscrypt.TrustedCertificateStore;
+import com.android.internal.os.Zygote;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
@@ -4117,6 +4120,19 @@
return MTE_NOT_CONTROLLED_BY_POLICY;
}
+ /**
+ * Get the current MTE state of the device.
+ *
+ * <a href="https://source.android.com/docs/security/test/memory-safety/arm-mte">
+ * Learn more about MTE</a>
+ *
+ * @return whether MTE is currently enabled on the device.
+ */
+ @FlaggedApi(FLAG_IS_MTE_POLICY_ENFORCED)
+ public static boolean isMtePolicyEnforced() {
+ return Zygote.nativeSupportsMemoryTagging();
+ }
+
/** Indicates that content protection is not controlled by policy, allowing user to choose. */
@FlaggedApi(android.view.contentprotection.flags.Flags.FLAG_MANAGE_DEVICE_POLICY_ENABLED)
public static final int CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY = 0;
@@ -17044,6 +17060,26 @@
}
/**
+ *
+ * Returns whether the device considers itself to be potentially stolen.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_THEFT_DETECTION)
+ @FlaggedApi(Flags.FLAG_DEVICE_THEFT_API_ENABLED)
+ public boolean isTheftDetectionTriggered() {
+ throwIfParentInstance("isTheftDetectionTriggered");
+ if (mService == null) {
+ return false;
+ }
+ try {
+ return mService.isTheftDetectionTriggered(mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns a {@link DevicePolicyResourcesManager} containing the required APIs to set, reset,
* and get device policy related resources.
*/
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index f2466ac..ca4a5ab 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -576,6 +576,8 @@
void setWifiSsidPolicy(String callerPackageName, in WifiSsidPolicy policy);
WifiSsidPolicy getWifiSsidPolicy(String callerPackageName);
+ boolean isTheftDetectionTriggered(String callerPackageName);
+
List<UserHandle> listForegroundAffiliatedUsers();
void setDrawables(in List<DevicePolicyDrawableResource> drawables);
void resetDrawables(in List<String> drawableIds);
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 726ddad..cbd8e5b 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -139,3 +139,10 @@
description: "Add Headless DO support."
bug: "289515470"
}
+
+flag {
+ name: "is_mte_policy_enforced"
+ namespace: "enterprise"
+ description: "Allow to query whether MTE is enabled or not to check for compliance for enterprise policy"
+ bug: "322777918"
+}
diff --git a/core/java/android/app/ondeviceintelligence/OWNERS b/core/java/android/app/ondeviceintelligence/OWNERS
new file mode 100644
index 0000000..6932ba2
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 1363385
+
+sandeepbandaru@google.com
+shivanker@google.com
+hackz@google.com
+volnov@google.com
+
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index a8dba51..cae4fab 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1565,6 +1565,14 @@
private Boolean requestRawExternalStorageAccess;
/**
+ * If {@code false}, this app does not allow its activities to be replaced by another app.
+ * Is set from application manifest application tag's allowCrossUidActivitySwitchFromBelow
+ * attribute.
+ * @hide
+ */
+ public boolean allowCrossUidActivitySwitchFromBelow = true;
+
+ /**
* Represents the default policy. The actual policy used will depend on other properties of
* the application, e.g. the target SDK version.
* @hide
@@ -1760,6 +1768,9 @@
+ Integer.toHexString(localeConfigRes));
}
pw.println(prefix + "enableOnBackInvokedCallback=" + isOnBackInvokedCallbackEnabled());
+ pw.println(prefix + "allowCrossUidActivitySwitchFromBelow="
+ + allowCrossUidActivitySwitchFromBelow);
+
}
pw.println(prefix + "createTimestamp=" + createTimestamp);
if (mKnownActivityEmbeddingCerts != null) {
@@ -1877,6 +1888,8 @@
proto.write(ApplicationInfoProto.Detail.NATIVE_HEAP_ZERO_INIT,
nativeHeapZeroInitialized);
}
+ proto.write(ApplicationInfoProto.Detail.ALLOW_CROSS_UID_ACTIVITY_SWITCH_FROM_BELOW,
+ allowCrossUidActivitySwitchFromBelow);
proto.end(detailToken);
}
if (!ArrayUtils.isEmpty(mKnownActivityEmbeddingCerts)) {
@@ -2002,6 +2015,7 @@
nativeHeapZeroInitialized = orig.nativeHeapZeroInitialized;
requestRawExternalStorageAccess = orig.requestRawExternalStorageAccess;
localeConfigRes = orig.localeConfigRes;
+ allowCrossUidActivitySwitchFromBelow = orig.allowCrossUidActivitySwitchFromBelow;
createTimestamp = SystemClock.uptimeMillis();
}
@@ -2106,6 +2120,8 @@
}
}
dest.writeInt(localeConfigRes);
+ dest.writeInt(allowCrossUidActivitySwitchFromBelow ? 1 : 0);
+
sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags);
}
@@ -2204,6 +2220,8 @@
}
}
localeConfigRes = source.readInt();
+ allowCrossUidActivitySwitchFromBelow = source.readInt() != 0;
+
mKnownActivityEmbeddingCerts = sForStringSet.unparcel(source);
if (mKnownActivityEmbeddingCerts.isEmpty()) {
mKnownActivityEmbeddingCerts = null;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 49c8a7c..2a67353 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2554,6 +2554,15 @@
public static final int INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST = -130;
/**
+ * Installation failed return code: if the system failed to install the package that
+ * {@link android.R.attr#multiArch} is true in its manifest because its packaged
+ * native code did not match all of the natively ABIs supported by the system.
+ *
+ * @hide
+ */
+ public static final int INSTALL_FAILED_MULTI_ARCH_NOT_MATCH_ALL_NATIVE_ABIS = -131;
+
+ /**
* App minimum aspect ratio set by the user which will override app-defined aspect ratio.
*
* @hide
@@ -10452,6 +10461,8 @@
case INSTALL_FAILED_SESSION_INVALID: return "INSTALL_FAILED_SESSION_INVALID";
case INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST:
return "INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST";
+ case INSTALL_FAILED_MULTI_ARCH_NOT_MATCH_ALL_NATIVE_ABIS:
+ return "INSTALL_FAILED_MULTI_ARCH_NOT_MATCH_ALL_NATIVE_ABIS";
default: return Integer.toString(status);
}
}
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
index b4fe7fe..53f56bc 100644
--- a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
+++ b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
@@ -18,8 +18,11 @@
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.graphics.ImageFormat;
+import android.hardware.camera2.params.ColorSpaceProfiles;
+import android.hardware.camera2.params.DynamicRangeProfiles;
import android.hardware.camera2.utils.SurfaceUtils;
import android.util.Size;
import android.view.Surface;
@@ -65,6 +68,8 @@
mOutputSurface.size = new android.hardware.camera2.extension.Size();
mOutputSurface.size.width = size.getWidth();
mOutputSurface.size.height = size.getHeight();
+ mOutputSurface.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
+ mOutputSurface.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
}
/**
@@ -95,4 +100,48 @@
public @ImageFormat.Format int getImageFormat() {
return mOutputSurface.imageFormat;
}
+
+ /**
+ * Return the dynamic range profile. The default
+ * dynamicRangeProfile is
+ * {@link android.hardware.camera2.params.DynamicRangeProfiles.STANDARD}
+ * unless specified by CameraOutputSurface.setDynamicRangeProfile.
+ */
+ @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+ public @DynamicRangeProfiles.Profile long getDynamicRangeProfile() {
+ return mOutputSurface.dynamicRangeProfile;
+ }
+
+ /**
+ * Return the color space. The default colorSpace is
+ * {@link android.hardware.camera2.params.ColorSpaceProfiles.UNSPECIFIED}
+ * unless specified by CameraOutputSurface.setColorSpace.
+ */
+ @SuppressLint("MethodNameUnits")
+ @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+ public int getColorSpace() {
+ return mOutputSurface.colorSpace;
+ }
+
+ /**
+ * Set the dynamic range profile. The default dynamicRangeProfile
+ * will be {@link android.hardware.camera2.params.DynamicRangeProfiles.STANDARD}
+ * unless explicitly set using this method.
+ */
+ @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+ public void setDynamicRangeProfile(
+ @DynamicRangeProfiles.Profile long dynamicRangeProfile) {
+ mOutputSurface.dynamicRangeProfile = dynamicRangeProfile;
+ }
+
+ /**
+ * Set the color space. The default colorSpace
+ * will be
+ * {@link android.hardware.camera2.params.ColorSpaceProfiles.UNSPECIFIED}
+ * unless explicitly set using this method.
+ */
+ @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+ public void setColorSpace(int colorSpace) {
+ mOutputSurface.colorSpace = colorSpace;
+ }
}
diff --git a/core/java/android/hardware/camera2/extension/OutputSurface.aidl b/core/java/android/hardware/camera2/extension/OutputSurface.aidl
index 8415379..02e160c 100644
--- a/core/java/android/hardware/camera2/extension/OutputSurface.aidl
+++ b/core/java/android/hardware/camera2/extension/OutputSurface.aidl
@@ -24,4 +24,6 @@
Surface surface;
Size size;
int imageFormat;
+ long dynamicRangeProfile;
+ int colorSpace;
}
diff --git a/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java b/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
index 0e6c1b3..69a6e9b 100644
--- a/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
@@ -15,15 +15,20 @@
*/
package android.hardware.camera2.params;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
-
+import android.annotation.SuppressLint;
+import android.graphics.ColorSpace;
+import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraExtensionCharacteristics.Extension;
import android.hardware.camera2.CameraExtensionSession;
import java.util.List;
import java.util.concurrent.Executor;
+import com.android.internal.camera.flags.Flags;
+
/**
* A class that aggregates all supported arguments for
* {@link CameraExtensionSession} initialization.
@@ -36,6 +41,7 @@
private OutputConfiguration mPostviewOutput = null;
private Executor mExecutor = null;
private CameraExtensionSession.StateCallback mCallback = null;
+ private int mColorSpace;
/**
* Create a new ExtensionSessionConfiguration
@@ -118,4 +124,55 @@
Executor getExecutor() {
return mExecutor;
}
+
+ /**
+ * Set a specific device-supported color space.
+ *
+ * <p>Clients can choose from any profile advertised as supported in
+ * {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES}
+ * queried using {@link ColorSpaceProfiles#getSupportedColorSpaces}.
+ * When set, the colorSpace will override the default color spaces of the output targets,
+ * or the color space implied by the dataSpace passed into an {@link ImageReader}'s
+ * constructor.</p>
+ */
+ @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+ public void setColorSpace(@NonNull ColorSpace.Named colorSpace) {
+ mColorSpace = colorSpace.ordinal();
+ for (OutputConfiguration outputConfiguration : mOutputs) {
+ outputConfiguration.setColorSpace(colorSpace);
+ }
+ if (mPostviewOutput != null) {
+ mPostviewOutput.setColorSpace(colorSpace);
+ }
+ }
+
+ /**
+ * Clear the color space, such that the default color space will be used.
+ */
+ @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+ public void clearColorSpace() {
+ mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
+ for (OutputConfiguration outputConfiguration : mOutputs) {
+ outputConfiguration.clearColorSpace();
+ }
+ if (mPostviewOutput != null) {
+ mPostviewOutput.clearColorSpace();
+ }
+ }
+
+ /**
+ * Return the current color space.
+ *
+ * @return the currently set color space, or null
+ * if not set
+ */
+ @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
+ @SuppressLint("MethodNameUnits")
+ public @Nullable ColorSpace getColorSpace() {
+ if (mColorSpace != ColorSpaceProfiles.UNSPECIFIED) {
+ return ColorSpace.get(ColorSpace.Named.values()[mColorSpace]);
+ } else {
+ return null;
+ }
+ }
}
diff --git a/core/java/android/hardware/devicestate/DeviceState.java b/core/java/android/hardware/devicestate/DeviceState.java
index 5a34905..8629354 100644
--- a/core/java/android/hardware/devicestate/DeviceState.java
+++ b/core/java/android/hardware/devicestate/DeviceState.java
@@ -16,18 +16,25 @@
package android.hardware.devicestate;
-import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
+import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE_IDENTIFIER;
+import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE_IDENTIFIER;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import com.android.internal.util.Preconditions;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Collections;
import java.util.Objects;
+import java.util.Set;
/**
* A state of the device defined by the {@link DeviceStateProvider} and managed by the
@@ -37,21 +44,29 @@
* state of the system. This is useful for variable-state devices, like foldable or rollable
* devices, that can be configured by users into differing hardware states, which each may have a
* different expected use case.
- * @hide
*
+ * @hide
* @see DeviceStateManager
*/
+@SystemApi
+@FlaggedApi(android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_PROPERTY_API)
public final class DeviceState {
/**
* Flag that indicates override requests should be cancelled when this device state becomes the
* base device state.
+ * @hide
+ * @deprecated use {@link #PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS}
*/
+ @Deprecated
public static final int FLAG_CANCEL_OVERRIDE_REQUESTS = 1 << 0;
/**
* Flag that indicates this device state is inaccessible for applications to be placed in. This
- * could be a device-state where the {@link DEFAULT_DISPLAY} is not enabled.
+ * could be a device-state where the {@link Display#DEFAULT_DISPLAY} is not enabled.
+ * @hide
+ * @deprecated use {@link #PROPERTY_APP_INACCESSIBLE}
*/
+ @Deprecated
public static final int FLAG_APP_INACCESSIBLE = 1 << 1;
/**
@@ -60,7 +75,10 @@
* through emulation and have no physical configuration to match.
*
* This flag indicates that the corresponding state can only be entered through emulation.
+ * @hide
+ * @deprecated use {@link #PROPERTY_EMULATED_ONLY}
*/
+ @Deprecated
public static final int FLAG_EMULATED_ONLY = 1 << 2;
/**
@@ -68,19 +86,28 @@
* requesting app is no longer on top. The app is considered not on top when (1) the top
* activity in the system is from a different app, (2) the device is in sleep mode, or
* (3) the keyguard shows up.
+ * @hide
+ * @deprecated use {@link #PROPERTY_POLICY_CANCEL_WHEN_REQUESTER_NOT_ON_TOP}
*/
+ @Deprecated
public static final int FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP = 1 << 3;
/**
* This flag indicates that the corresponding state should be disabled when the device is
* overheating and reaching the critical status.
+ * @hide
+ * @deprecated use {@link #PROPERTY_POLICY_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL}
*/
+ @Deprecated
public static final int FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL = 1 << 4;
/**
* This flag indicates that the corresponding state should be disabled when power save mode
* is enabled.
+ * @hide
+ * @deprecated use {@link #PROPERTY_POLICY_UNSUPPORTED_WHEN_POWER_SAVE_MODE}
*/
+ @Deprecated
public static final int FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE = 1 << 5;
/** @hide */
@@ -92,11 +119,157 @@
FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL,
FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE
})
+ @Deprecated
@Retention(RetentionPolicy.SOURCE)
public @interface DeviceStateFlags {}
+ /**
+ * Property that indicates that a fold-in style foldable device is currently in a fully closed
+ * configuration.
+ */
+ public static final int PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED = 1;
+
+ /**
+ * Property that indicates that a fold-in style foldable device is currently in a half-opened
+ * configuration. This signifies that the device's hinge is positioned somewhere around 90
+ * degrees. Checking for display configuration properties as well can provide information
+ * on which display is currently active.
+ */
+ public static final int PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN = 2;
+
+ /**
+ * Property that indicates that a fold-in style foldable device is currently in a fully open
+ * configuration.
+ */
+ public static final int PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN = 3;
+
+ /**
+ * Property that indicates override requests should be cancelled when the device is physically
+ * put into this state.
+ * @hide
+ */
+ public static final int PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS = 4;
+
+ /**
+ * This property indicates that the corresponding state should be automatically canceled when
+ * the requesting app is no longer on top. The app is considered not on top when (1) the top
+ * activity in the system is from a different app, (2) the device is in sleep mode, or
+ * (3) the keyguard shows up.
+ * @hide
+ */
+ public static final int PROPERTY_POLICY_CANCEL_WHEN_REQUESTER_NOT_ON_TOP = 5;
+
+ /**
+ * This property indicates that the corresponding state should be disabled when the device is
+ * overheating and reaching the critical status.
+ * @hide
+ */
+ public static final int PROPERTY_POLICY_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL = 6;
+
+ /**
+ * This property indicates that the corresponding state should be disabled when power save mode
+ * is enabled.
+ * @hide
+ */
+ public static final int PROPERTY_POLICY_UNSUPPORTED_WHEN_POWER_SAVE_MODE = 7;
+
+ /**
+ * This property denotes that this state is available for applications to request and the system
+ * server should deny any request that comes from a process that does not hold the
+ * CONTROL_DEVICE_STATE permission if it is requesting a state that does not have this property
+ * on it.
+ * @hide
+ */
+ @TestApi
+ public static final int PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST = 8;
+
+ /**
+ * Property that indicates this device state is inaccessible for applications to be made
+ * visible to the user. This could be a device-state where the {@link Display#DEFAULT_DISPLAY}
+ * is not enabled.
+ * @hide
+ */
+ public static final int PROPERTY_APP_INACCESSIBLE = 9;
+
+ /**
+ * This property indidcates that this state can only be entered through emulation and has no
+ * physical configuration to match.
+ */
+ public static final int PROPERTY_EMULATED_ONLY = 10;
+
+ /**
+ * Property that indicates that the outer display area of a foldable device is currently the
+ * primary display area.
+ *
+ * Note: This does not necessarily mean that the outer display area is the
+ * @link Display#DEFAULT_DISPLAY}.
+ */
+ public static final int PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY = 11;
+
+ /**
+ * Property that indicates that the inner display area of a foldable device is currently the
+ * primary display area.
+ *
+ * Note: This does not necessarily mean that the inner display area is the
+ * {@link Display#DEFAULT_DISPLAY}.
+ */
+ public static final int PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY = 12;
+
+ /**
+ * Property that indicates that this device state will attempt to trigger the device to go to
+ * sleep.
+ */
+ public static final int PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP = 13;
+
+ /**
+ * Property that indicates that this device state will attempt to trigger the device to wake up.
+ */
+ public static final int PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE = 14;
+
+ /**
+ * Property that indicates that an external display has been connected to the device. Specifics
+ * around display mode or properties around the display should be gathered through
+ * {@link android.hardware.display.DisplayManager}
+ */
+ public static final int PROPERTY_EXTENDED_DEVICE_STATE_EXTERNAL_DISPLAY = 15;
+ /**
+ * Property that indicates that this state corresponds to the device state for rear display
+ * mode. This means that the active display is facing the same direction as the rear camera.
+ */
+ public static final int PROPERTY_FEATURE_REAR_DISPLAY = 16;
+
+ /**
+ * Property that indicates that this state corresponds to the device state where both displays
+ * on a foldable are active, with the internal display being the default display.
+ */
+ public static final int PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT = 17;
+
+ /** @hide */
+ @IntDef(prefix = {"PROPERTY_"}, flag = true, value = {
+ PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED,
+ PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN,
+ PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN,
+ PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS,
+ PROPERTY_POLICY_CANCEL_WHEN_REQUESTER_NOT_ON_TOP,
+ PROPERTY_POLICY_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL,
+ PROPERTY_POLICY_UNSUPPORTED_WHEN_POWER_SAVE_MODE,
+ PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST,
+ PROPERTY_APP_INACCESSIBLE,
+ PROPERTY_EMULATED_ONLY,
+ PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
+ PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY,
+ PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP,
+ PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE,
+ PROPERTY_EXTENDED_DEVICE_STATE_EXTERNAL_DISPLAY,
+ PROPERTY_FEATURE_REAR_DISPLAY,
+ PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ public @interface DeviceStateProperties {}
+
/** Unique identifier for the device state. */
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE)
+ @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to = MAXIMUM_DEVICE_STATE_IDENTIFIER)
private final int mIdentifier;
/** String description of the device state. */
@@ -106,20 +279,49 @@
@DeviceStateFlags
private final int mFlags;
+ private final Set<@DeviceStateProperties Integer> mProperties;
+
+ /**
+ * @deprecated Deprecated in favor of {@link #DeviceState(int, String, Set)}
+ * @hide
+ */
+ // TODO(b/325124054): Make non-default and remove deprecated callback methods.
+ @TestApi
+ @Deprecated
public DeviceState(
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
+ @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to =
+ MAXIMUM_DEVICE_STATE_IDENTIFIER) int identifier,
@NonNull String name,
@DeviceStateFlags int flags) {
- Preconditions.checkArgumentInRange(identifier, MINIMUM_DEVICE_STATE, MAXIMUM_DEVICE_STATE,
+ Preconditions.checkArgumentInRange(identifier, MINIMUM_DEVICE_STATE_IDENTIFIER,
+ MAXIMUM_DEVICE_STATE_IDENTIFIER,
"identifier");
mIdentifier = identifier;
mName = name;
mFlags = flags;
+ mProperties = Collections.emptySet();
+ }
+
+ /** @hide */
+ @TestApi
+ public DeviceState(
+ @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to =
+ MAXIMUM_DEVICE_STATE_IDENTIFIER) int identifier,
+ @NonNull String name,
+ @NonNull Set<@DeviceStateProperties Integer> properties) {
+ Preconditions.checkArgumentInRange(identifier, MINIMUM_DEVICE_STATE_IDENTIFIER,
+ MAXIMUM_DEVICE_STATE_IDENTIFIER,
+ "identifier");
+
+ mIdentifier = identifier;
+ mName = name;
+ mProperties = Set.copyOf(properties);
+ mFlags = 0;
}
/** Returns the unique identifier for the device state. */
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE)
+ @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER)
public int getIdentifier() {
return mIdentifier;
}
@@ -130,6 +332,12 @@
return mName;
}
+ /**
+ * @hide
+ * @deprecated in favor of {@link #hasProperty(int)} method
+ */
+ // TODO(b/325124054): Make non-default and remove deprecated callback methods.
+ @Deprecated
@DeviceStateFlags
public int getFlags() {
return mFlags;
@@ -138,9 +346,9 @@
@Override
public String toString() {
return "DeviceState{" + "identifier=" + mIdentifier + ", name='" + mName + '\''
- + ", app_accessible=" + !hasFlag(FLAG_APP_INACCESSIBLE)
+ + ", app_accessible=" + !hasProperty(PROPERTY_APP_INACCESSIBLE)
+ ", cancel_when_requester_not_on_top="
- + hasFlag(FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP)
+ + hasProperty(PROPERTY_POLICY_CANCEL_WHEN_REQUESTER_NOT_ON_TOP)
+ "}";
}
@@ -151,17 +359,40 @@
DeviceState that = (DeviceState) o;
return mIdentifier == that.mIdentifier
&& Objects.equals(mName, that.mName)
- && mFlags == that.mFlags;
+ && Objects.equals(mProperties, that.mProperties);
}
@Override
public int hashCode() {
- return Objects.hash(mIdentifier, mName, mFlags);
+ return Objects.hash(mIdentifier, mName, mProperties);
}
/** Checks if a specific flag is set
+ * @hide
+ * @deprecated in favor of {@link #hasProperty(int)}
*/
+ // TODO(b/325124054): Make non-default and remove deprecated callback methods.
+ @Deprecated
public boolean hasFlag(int flagToCheckFor) {
return (mFlags & flagToCheckFor) == flagToCheckFor;
}
+
+ /**
+ * Checks if a specific property is set on this state
+ */
+ public boolean hasProperty(@DeviceStateProperties int propertyToCheckFor) {
+ return mProperties.contains(propertyToCheckFor);
+ }
+
+ /**
+ * Checks if a list of properties are all set on this state
+ */
+ public boolean hasProperties(@NonNull @DeviceStateProperties int... properties) {
+ for (int i = 0; i < properties.length; i++) {
+ if (mProperties.contains(properties[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
index 6a667fe..8b4d43e 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManager.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -18,15 +18,19 @@
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
import com.android.internal.util.ArrayUtils;
+import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -36,7 +40,8 @@
*
* @hide
*/
-@TestApi
+@SystemApi
+@FlaggedApi(android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_PROPERTY_API)
@SystemService(Context.DEVICE_STATE_SERVICE)
public final class DeviceStateManager {
/**
@@ -46,11 +51,19 @@
*/
public static final int INVALID_DEVICE_STATE = -1;
- /** The minimum allowed device state identifier. */
- public static final int MINIMUM_DEVICE_STATE = 0;
+ /**
+ * The minimum allowed device state identifier.
+ * @hide
+ */
+ @TestApi
+ public static final int MINIMUM_DEVICE_STATE_IDENTIFIER = 0;
- /** The maximum allowed device state identifier. */
- public static final int MAXIMUM_DEVICE_STATE = 255;
+ /**
+ * The maximum allowed device state identifier.
+ * @hide
+ */
+ @TestApi
+ public static final int MAXIMUM_DEVICE_STATE_IDENTIFIER = 10000;
/**
* Intent needed to launch the rear display overlay activity from SysUI
@@ -83,13 +96,27 @@
/**
* Returns the list of device states that are supported and can be requested with
* {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
+ * @deprecated use {@link #getSupportedDeviceStates()}
+ * @hide
*/
+ // TODO(b/325124054): Make non-default and remove deprecated callback methods.
+ @TestApi
+ @Deprecated
@NonNull
public int[] getSupportedStates() {
return mGlobal.getSupportedStates();
}
/**
+ * Returns the list of device states that are supported and can be requested with
+ * {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
+ */
+ @NonNull
+ public List<DeviceState> getSupportedDeviceStates() {
+ return mGlobal.getSupportedDeviceStates();
+ }
+
+ /**
* Submits a {@link DeviceStateRequest request} to modify the device state.
* <p>
* By default, the request is kept active until one of the following occurs:
@@ -107,7 +134,10 @@
* the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission is held.
*
* @see DeviceStateRequest
+ * @hide
*/
+ @SuppressLint("RequiresPermission") // Lint doesn't handle conditional permission checks today
+ @TestApi
@RequiresPermission(value = android.Manifest.permission.CONTROL_DEVICE_STATE,
conditional = true)
public void requestState(@NonNull DeviceStateRequest request,
@@ -124,7 +154,10 @@
*
* @throws SecurityException if the caller is neither the current top-focused activity nor if
* the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission is held.
+ * @hide
*/
+ @SuppressLint("RequiresPermission") // Lint doesn't handle conditional permission checks today
+ @TestApi
@RequiresPermission(value = android.Manifest.permission.CONTROL_DEVICE_STATE,
conditional = true)
public void cancelStateRequest() {
@@ -151,11 +184,11 @@
* emulated override requests take priority.
*
* @throws IllegalArgumentException if the requested state is unsupported.
- * @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission.
*
* @see DeviceStateRequest
+ * @hide
*/
+ @TestApi
@RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE)
public void requestBaseStateOverride(@NonNull DeviceStateRequest request,
@Nullable @CallbackExecutor Executor executor,
@@ -169,9 +202,9 @@
* <p>
* This method is noop if there is no base state request currently active.
*
- * @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission.
+ * @hide
*/
+ @TestApi
@RequiresPermission(Manifest.permission.CONTROL_DEVICE_STATE)
public void cancelBaseStateOverride() {
mGlobal.cancelBaseStateOverride();
@@ -209,10 +242,31 @@
* @param supportedStates the new supported states.
*
* @see DeviceStateManager#getSupportedStates()
+ * @deprecated use {@link #onSupportedStatesChanged(List)}
+ * @hide
*/
+ // TODO(b/325124054): Make non-default and remove deprecated callback methods.
+ @TestApi
+ @Deprecated
default void onSupportedStatesChanged(@NonNull int[] supportedStates) {}
/**
+ * Called in response to a change in the states supported by the device.
+ * <p>
+ * Guaranteed to be called once on registration of the callback with the initial value and
+ * then on every subsequent change in the supported states.
+ *
+ * The supported device states may change due to certain states becoming unavailable
+ * due to device configuration or device conditions such as if the device is too hot or
+ * external monitors have been connected.
+ *
+ * @param supportedStates the new supported states.
+ *
+ * @see DeviceStateManager#getSupportedDeviceStates()
+ */
+ default void onSupportedStatesChanged(@NonNull List<DeviceState> supportedStates) {}
+
+ /**
* Called in response to a change in the base device state.
* <p>
* The base state is the state of the device without considering any requests made through
@@ -224,7 +278,13 @@
* then on every subsequent change in the non-override state.
*
* @param state the new base device state.
+ * @deprecated use {@link #onDeviceStateChanged(DeviceState)} and query for physical
+ * properties that are relevant to your needs.
+ * @hide
*/
+ // TODO(b/325124054): Make non-default and remove deprecated callback methods.
+ @TestApi
+ @Deprecated
default void onBaseStateChanged(int state) {}
/**
@@ -234,8 +294,24 @@
* then on every subsequent change in device state.
*
* @param state the new device state.
+ * @deprecated use {@link #onDeviceStateChanged(DeviceState)}
+ * @hide
*/
+ // TODO(b/325124054): Make non-default and remove deprecated callback methods.
+ @TestApi
+ @Deprecated
void onStateChanged(int state);
+
+ /**
+ * Called in response to device state changes.
+ * <p>
+ * Guaranteed to be called once on registration of the callback with the initial value and
+ * then on every subsequent change in device state.
+ *
+ * @param state the new device state.
+ */
+ // TODO(b/325124054): Make non-default and remove deprecated callback methods.
+ default void onDeviceStateChanged(@NonNull DeviceState state) {}
}
/**
@@ -247,6 +323,7 @@
public static class FoldStateListener implements DeviceStateCallback {
private final int[] mFoldedDeviceStates;
private final Consumer<Boolean> mDelegate;
+ private final android.hardware.devicestate.feature.flags.FeatureFlags mFeatureFlags;
@Nullable
private Boolean lastResult;
@@ -259,11 +336,23 @@
mFoldedDeviceStates = context.getResources().getIntArray(
com.android.internal.R.array.config_foldedDeviceStates);
mDelegate = listener;
+ mFeatureFlags = new android.hardware.devicestate.feature.flags.FeatureFlagsImpl();
}
@Override
- public final void onStateChanged(int state) {
- final boolean folded = ArrayUtils.contains(mFoldedDeviceStates, state);
+ public final void onStateChanged(int state) {}
+
+ @Override
+ public final void onDeviceStateChanged(@NonNull DeviceState deviceState) {
+ final boolean folded;
+ if (mFeatureFlags.deviceStatePropertyApi()) {
+ // TODO(b/325124054): Update when system server refactor is completed
+ folded = deviceState.hasProperty(
+ DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)
+ || ArrayUtils.contains(mFoldedDeviceStates, deviceState.getIdentifier());
+ } else {
+ folded = ArrayUtils.contains(mFoldedDeviceStates, deviceState.getIdentifier());
+ }
if (lastResult == null || !lastResult.equals(folded)) {
lastResult = folded;
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
index c379188..6db5aee 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.app.ActivityThread;
import android.content.Context;
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
import android.os.Binder;
@@ -32,9 +33,13 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import java.util.concurrent.Executor;
/**
@@ -50,12 +55,18 @@
private static final String TAG = "DeviceStateManagerGlobal";
private static final boolean DEBUG = Build.IS_DEBUGGABLE;
+ // TODO(b/325124054): Remove when system server refactor is completed
+ private static int[] sFoldedDeviceStates = new int[0];
+
/**
* Returns an instance of {@link DeviceStateManagerGlobal}. May return {@code null} if a
* connection with the device state service couldn't be established.
*/
@Nullable
public static DeviceStateManagerGlobal getInstance() {
+ // TODO(b/325124054): Remove when system server refactor is completed
+ instantiateFoldedStateArray();
+
synchronized (DeviceStateManagerGlobal.class) {
if (sInstance == null) {
IBinder b = ServiceManager.getService(Context.DEVICE_STATE_SERVICE);
@@ -68,6 +79,16 @@
}
}
+ // TODO(b/325124054): Remove when system server refactor is completed
+ // TODO(b/325330654): Investigate if we need a Context passed in to DSMGlobal
+ private static void instantiateFoldedStateArray() {
+ Context context = ActivityThread.currentApplication();
+ if (context != null) {
+ sFoldedDeviceStates = context.getResources().getIntArray(
+ com.android.internal.R.array.config_foldedDeviceStates);
+ }
+ }
+
private final Object mLock = new Object();
@NonNull
private final IDeviceStateManager mDeviceStateManager;
@@ -116,6 +137,32 @@
}
/**
+ * Returns the {@link List} of supported device states.
+ *
+ * @see DeviceStateManager#getSupportedDeviceStates()
+ */
+ public List<DeviceState> getSupportedDeviceStates() {
+ synchronized (mLock) {
+ final DeviceStateInfo currentInfo;
+ if (mLastReceivedInfo != null) {
+ // If we have mLastReceivedInfo a callback is registered for this instance and it
+ // is receiving the most recent info from the server. Use that info here.
+ currentInfo = mLastReceivedInfo;
+ } else {
+ // If mLastReceivedInfo is null there is no registered callback so we manually
+ // fetch the current info.
+ try {
+ currentInfo = mDeviceStateManager.getDeviceStateInfo();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ return createDeviceStateList(currentInfo.supportedStates);
+ }
+ }
+
+ /**
* Submits a {@link DeviceStateRequest request} to modify the device state.
*
* @see DeviceStateManager#requestState(DeviceStateRequest, Executor,
@@ -241,8 +288,10 @@
final int[] supportedStates = Arrays.copyOf(mLastReceivedInfo.supportedStates,
mLastReceivedInfo.supportedStates.length);
wrapper.notifySupportedStatesChanged(supportedStates);
+ wrapper.notifySupportedDeviceStatesChanged(createDeviceStateList(supportedStates));
wrapper.notifyBaseStateChanged(mLastReceivedInfo.baseState);
wrapper.notifyStateChanged(mLastReceivedInfo.currentState);
+ wrapper.notifyDeviceStateChanged(createDeviceState(mLastReceivedInfo.currentState));
}
}
}
@@ -327,6 +376,8 @@
final int[] supportedStates = Arrays.copyOf(info.supportedStates,
info.supportedStates.length);
callbacks.get(i).notifySupportedStatesChanged(supportedStates);
+ callbacks.get(i).notifySupportedDeviceStatesChanged(
+ createDeviceStateList(supportedStates));
}
}
if ((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0) {
@@ -337,6 +388,7 @@
if ((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0) {
for (int i = 0; i < callbacks.size(); i++) {
callbacks.get(i).notifyStateChanged(info.currentState);
+ callbacks.get(i).notifyDeviceStateChanged(createDeviceState(info.currentState));
}
}
}
@@ -369,6 +421,36 @@
}
}
+ /**
+ * Creates a {@link DeviceState} object from a device state identifier, with the
+ * {@link DeviceState} property that corresponds to what display is primary.
+ *
+ */
+ // TODO(b/325124054): Remove when system server refactor is completed
+ @NonNull
+ private DeviceState createDeviceState(int stateIdentifier) {
+ final Set<@DeviceState.DeviceStateProperties Integer> properties = new HashSet<>();
+ if (ArrayUtils.contains(sFoldedDeviceStates, stateIdentifier)) {
+ properties.add(DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY);
+ } else {
+ properties.add(DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY);
+ }
+ return new DeviceState(stateIdentifier, "" /* name */, properties);
+ }
+
+ /**
+ * Creates a list of {@link DeviceState} objects from an array of state identifiers.
+ */
+ // TODO(b/325124054): Remove when system server refactor is completed
+ @NonNull
+ private List<DeviceState> createDeviceStateList(int[] supportedStates) {
+ List<DeviceState> deviceStateList = new ArrayList<>();
+ for (int i = 0; i < supportedStates.length; i++) {
+ deviceStateList.add(createDeviceState(supportedStates[i]));
+ }
+ return deviceStateList;
+ }
+
private final class DeviceStateManagerCallback extends IDeviceStateManagerCallback.Stub {
@Override
public void onDeviceStateInfoChanged(DeviceStateInfo info) {
@@ -403,6 +485,11 @@
mDeviceStateCallback.onSupportedStatesChanged(newSupportedStates));
}
+ void notifySupportedDeviceStatesChanged(List<DeviceState> newSupportedDeviceStates) {
+ mExecutor.execute(() ->
+ mDeviceStateCallback.onSupportedStatesChanged(newSupportedDeviceStates));
+ }
+
void notifyBaseStateChanged(int newBaseState) {
execute("notifyBaseStateChanged",
() -> mDeviceStateCallback.onBaseStateChanged(newBaseState));
@@ -413,6 +500,11 @@
() -> mDeviceStateCallback.onStateChanged(newDeviceState));
}
+ void notifyDeviceStateChanged(DeviceState newDeviceState) {
+ execute("notifyDeviceStateChanged",
+ () -> mDeviceStateCallback.onDeviceStateChanged(newDeviceState));
+ }
+
private void execute(String traceName, Runnable r) {
mExecutor.execute(() -> {
if (DEBUG) {
diff --git a/core/java/android/hardware/devicestate/feature/flags.aconfig b/core/java/android/hardware/devicestate/feature/flags.aconfig
new file mode 100644
index 0000000..73a9e34
--- /dev/null
+++ b/core/java/android/hardware/devicestate/feature/flags.aconfig
@@ -0,0 +1,9 @@
+package: "android.hardware.devicestate.feature.flags"
+
+flag {
+ name: "device_state_property_api"
+ namespace: "windowing_sdk"
+ description: "Updated DeviceState hasProperty API"
+ bug: "293636629"
+ is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index e8c8b5a..9218cb8 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -111,3 +111,22 @@
description: "When the flag is off no permissions can be device aware"
bug: "274852670"
}
+
+flag {
+ name: "get_emergency_role_holder_api_enabled"
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "Enables the getEmergencyRoleHolder API."
+ bug: "323157319"
+}
+
+flag {
+ name: "new_permission_gid_enabled"
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "Enable new permission GID implementation"
+ bug: "325137277"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/service/ondeviceintelligence/OWNERS b/core/java/android/service/ondeviceintelligence/OWNERS
new file mode 100644
index 0000000..09774f7
--- /dev/null
+++ b/core/java/android/service/ondeviceintelligence/OWNERS
@@ -0,0 +1 @@
+file:/core/java/android/app/ondeviceintelligence/OWNERS
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 2028c40..9db8aa1 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -273,7 +273,7 @@
outerwidth /* ellipsizedWidth */, null /* ellipsize */, 1 /* maxLines */,
BREAK_STRATEGY_SIMPLE, HYPHENATION_FREQUENCY_NONE, null /* leftIndents */,
null /* rightIndents */, JUSTIFICATION_MODE_NONE, LineBreakConfig.NONE, false,
- null);
+ false /* shiftDrawingOffsetForStartOverhang */, null);
mEllipsizedWidth = outerwidth;
mEllipsizedStart = 0;
@@ -346,7 +346,8 @@
ellipsizedWidth, ellipsize, 1 /* maxLines */,
BREAK_STRATEGY_SIMPLE, HYPHENATION_FREQUENCY_NONE, null /* leftIndents */,
null /* rightIndents */, JUSTIFICATION_MODE_NONE,
- LineBreakConfig.NONE, metrics, false /* useBoundsForWidth */, null);
+ LineBreakConfig.NONE, metrics, false /* useBoundsForWidth */,
+ false /* shiftDrawingOffsetForStartOverhang */, null);
}
/** @hide */
@@ -363,12 +364,14 @@
TextUtils.TruncateAt ellipsize,
Metrics metrics,
boolean useBoundsForWidth,
+ boolean shiftDrawingOffsetForStartOverhang,
@Nullable Paint.FontMetrics minimumFontMetrics) {
this(text, paint, width, align, TextDirectionHeuristics.LTR,
spacingMult, spacingAdd, includePad, fallbackLineSpacing, ellipsizedWidth,
ellipsize, 1 /* maxLines */, Layout.BREAK_STRATEGY_SIMPLE,
Layout.HYPHENATION_FREQUENCY_NONE, null, null, Layout.JUSTIFICATION_MODE_NONE,
- LineBreakConfig.NONE, metrics, useBoundsForWidth, minimumFontMetrics);
+ LineBreakConfig.NONE, metrics, useBoundsForWidth,
+ shiftDrawingOffsetForStartOverhang, minimumFontMetrics);
}
/* package */ BoringLayout(
@@ -392,12 +395,14 @@
LineBreakConfig lineBreakConfig,
Metrics metrics,
boolean useBoundsForWidth,
+ boolean shiftDrawingOffsetForStartOverhang,
@Nullable Paint.FontMetrics minimumFontMetrics) {
super(text, paint, width, align, textDir, spacingMult, spacingAdd, includePad,
fallbackLineSpacing, ellipsizedWidth, ellipsize, maxLines, breakStrategy,
hyphenationFrequency, leftIndents, rightIndents, justificationMode,
- lineBreakConfig, useBoundsForWidth, minimumFontMetrics);
+ lineBreakConfig, useBoundsForWidth, shiftDrawingOffsetForStartOverhang,
+ minimumFontMetrics);
boolean trust;
@@ -712,7 +717,7 @@
int cursorOffset) {
if (mDirect != null && highlight == null) {
float leftShift = 0;
- if (getUseBoundsForWidth()) {
+ if (getUseBoundsForWidth() && getShiftDrawingOffsetForStartOverhang()) {
RectF drawingRect = computeDrawingBoundingBox();
if (drawingRect.left < 0) {
leftShift = -drawingRect.left;
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 9286049..cce4f7b 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -25,6 +25,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Paint;
import android.graphics.Rect;
@@ -317,6 +318,35 @@
}
/**
+ * Set true for shifting the drawing x offset for showing overhang at the start position.
+ *
+ * This flag is ignored if the {@link #getUseBoundsForWidth()} is false.
+ *
+ * If this value is false, the Layout draws text from the zero even if there is a glyph
+ * stroke in a region where the x coordinate is negative.
+ *
+ * If this value is true, the Layout draws text with shifting the x coordinate of the
+ * drawing bounding box.
+ *
+ * This value is false by default.
+ *
+ * @param shiftDrawingOffsetForStartOverhang true for shifting the drawing offset for
+ * showing the stroke that is in the region where
+ * the x coordinate is negative.
+ * @see #setUseBoundsForWidth(boolean)
+ * @see #getUseBoundsForWidth()
+ */
+ @NonNull
+ // The corresponding getter is getShiftDrawingOffsetForStartOverhang()
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+ public Builder setShiftDrawingOffsetForStartOverhang(
+ boolean shiftDrawingOffsetForStartOverhang) {
+ mShiftDrawingOffsetForStartOverhang = shiftDrawingOffsetForStartOverhang;
+ return this;
+ }
+
+ /**
* Set the minimum font metrics used for line spacing.
*
* <p>
@@ -386,6 +416,7 @@
private int mEllipsizedWidth;
private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
private boolean mUseBoundsForWidth;
+ private boolean mShiftDrawingOffsetForStartOverhang;
private @Nullable Paint.FontMetrics mMinimumFontMetrics;
private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
@@ -462,7 +493,8 @@
false /* fallbackLineSpacing */, ellipsizedWidth, ellipsize,
Integer.MAX_VALUE /* maxLines */, breakStrategy, hyphenationFrequency,
null /* leftIndents */, null /* rightIndents */, justificationMode,
- lineBreakConfig, false /* useBoundsForWidth */, null /* minimumFontMetrics */);
+ lineBreakConfig, false /* useBoundsForWidth */, false,
+ null /* minimumFontMetrics */);
final Builder b = Builder.obtain(base, paint, width)
.setAlignment(align)
@@ -488,7 +520,8 @@
b.mIncludePad, b.mFallbackLineSpacing, b.mEllipsizedWidth, b.mEllipsize,
Integer.MAX_VALUE /* maxLines */, b.mBreakStrategy, b.mHyphenationFrequency,
null /* leftIndents */, null /* rightIndents */, b.mJustificationMode,
- b.mLineBreakConfig, b.mUseBoundsForWidth, b.mMinimumFontMetrics);
+ b.mLineBreakConfig, b.mUseBoundsForWidth, b.mShiftDrawingOffsetForStartOverhang,
+ b.mMinimumFontMetrics);
mDisplay = b.mDisplay;
mIncludePad = b.mIncludePad;
@@ -516,6 +549,7 @@
mBase = b.mBase;
mFallbackLineSpacing = b.mFallbackLineSpacing;
mUseBoundsForWidth = b.mUseBoundsForWidth;
+ mShiftDrawingOffsetForStartOverhang = b.mShiftDrawingOffsetForStartOverhang;
mMinimumFontMetrics = b.mMinimumFontMetrics;
if (b.mEllipsize != null) {
mInts = new PackedIntVector(COLUMNS_ELLIPSIZE);
@@ -713,6 +747,7 @@
.setAddLastLineLineSpacing(!islast)
.setIncludePad(false)
.setUseBoundsForWidth(mUseBoundsForWidth)
+ .setShiftDrawingOffsetForStartOverhang(mShiftDrawingOffsetForStartOverhang)
.setMinimumFontMetrics(mMinimumFontMetrics)
.setCalculateBounds(true);
@@ -1392,6 +1427,7 @@
private Rect mTempRect = new Rect();
private boolean mUseBoundsForWidth;
+ private boolean mShiftDrawingOffsetForStartOverhang;
@Nullable Paint.FontMetrics mMinimumFontMetrics;
@UnsupportedAppUsage
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index e5d199a..8e52af3 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -44,6 +44,7 @@
import android.text.style.ParagraphStyle;
import android.text.style.ReplacementSpan;
import android.text.style.TabStopSpan;
+import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -299,7 +300,7 @@
this(text, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
spacingMult, spacingAdd, false, false, 0, null, Integer.MAX_VALUE,
BREAK_STRATEGY_SIMPLE, HYPHENATION_FREQUENCY_NONE, null, null,
- JUSTIFICATION_MODE_NONE, LineBreakConfig.NONE, false, null);
+ JUSTIFICATION_MODE_NONE, LineBreakConfig.NONE, false, false, null);
}
/**
@@ -349,6 +350,7 @@
int justificationMode,
LineBreakConfig lineBreakConfig,
boolean useBoundsForWidth,
+ boolean shiftDrawingOffsetForStartOverhang,
Paint.FontMetrics minimumFontMetrics
) {
@@ -384,6 +386,7 @@
mJustificationMode = justificationMode;
mLineBreakConfig = lineBreakConfig;
mUseBoundsForWidth = useBoundsForWidth;
+ mShiftDrawingOffsetForStartOverhang = shiftDrawingOffsetForStartOverhang;
mMinimumFontMetrics = minimumFontMetrics;
}
@@ -465,7 +468,7 @@
@Nullable Paint selectionPaint,
int cursorOffsetVertical) {
float leftShift = 0;
- if (mUseBoundsForWidth) {
+ if (mUseBoundsForWidth && mShiftDrawingOffsetForStartOverhang) {
RectF drawingRect = computeDrawingBoundingBox();
if (drawingRect.left < 0) {
leftShift = -drawingRect.left;
@@ -3414,6 +3417,7 @@
private int mJustificationMode;
private LineBreakConfig mLineBreakConfig;
private boolean mUseBoundsForWidth;
+ private boolean mShiftDrawingOffsetForStartOverhang;
private @Nullable Paint.FontMetrics mMinimumFontMetrics;
private TextLine.LineInfo mLineInfo = null;
@@ -3873,6 +3877,35 @@
}
/**
+ * Set true for shifting the drawing x offset for showing overhang at the start position.
+ *
+ * This flag is ignored if the {@link #getUseBoundsForWidth()} is false.
+ *
+ * If this value is false, the Layout draws text from the zero even if there is a glyph
+ * stroke in a region where the x coordinate is negative.
+ *
+ * If this value is true, the Layout draws text with shifting the x coordinate of the
+ * drawing bounding box.
+ *
+ * This value is false by default.
+ *
+ * @param shiftDrawingOffsetForStartOverhang true for shifting the drawing offset for
+ * showing the stroke that is in the region where
+ * the x coordinate is negative.
+ * @see #setUseBoundsForWidth(boolean)
+ * @see #getUseBoundsForWidth()
+ */
+ @NonNull
+ // The corresponding getter is getShiftDrawingOffsetForStartOverhang()
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+ public Builder setShiftDrawingOffsetForStartOverhang(
+ boolean shiftDrawingOffsetForStartOverhang) {
+ mShiftDrawingOffsetForStartOverhang = shiftDrawingOffsetForStartOverhang;
+ return this;
+ }
+
+ /**
* Set the minimum font metrics used for line spacing.
*
* <p>
@@ -3948,6 +3981,7 @@
.setJustificationMode(mJustificationMode)
.setLineBreakConfig(mLineBreakConfig)
.setUseBoundsForWidth(mUseBoundsForWidth)
+ .setShiftDrawingOffsetForStartOverhang(mShiftDrawingOffsetForStartOverhang)
.build();
} else {
return new BoringLayout(
@@ -3955,7 +3989,7 @@
mIncludePad, mFallbackLineSpacing, mEllipsizedWidth, mEllipsize, mMaxLines,
mBreakStrategy, mHyphenationFrequency, mLeftIndents, mRightIndents,
mJustificationMode, mLineBreakConfig, metrics, mUseBoundsForWidth,
- mMinimumFontMetrics);
+ mShiftDrawingOffsetForStartOverhang, mMinimumFontMetrics);
}
}
@@ -3980,6 +4014,7 @@
private int mJustificationMode = JUSTIFICATION_MODE_NONE;
private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
private boolean mUseBoundsForWidth;
+ private boolean mShiftDrawingOffsetForStartOverhang;
private Paint.FontMetrics mMinimumFontMetrics;
}
@@ -4294,6 +4329,20 @@
}
/**
+ * Returns true if shifting drawing offset for start overhang.
+ *
+ * @return True if shifting drawing offset for start overhang.
+ * @see android.widget.TextView#setShiftDrawingOffsetForStartOverhang(boolean)
+ * @see TextView#getShiftDrawingOffsetForStartOverhang()
+ * @see StaticLayout.Builder#setShiftDrawingOffsetForStartOverhang(boolean)
+ * @see DynamicLayout.Builder#setShiftDrawingOffsetForStartOverhang(boolean)
+ */
+ @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+ public boolean getShiftDrawingOffsetForStartOverhang() {
+ return mShiftDrawingOffsetForStartOverhang;
+ }
+
+ /**
* Get the minimum font metrics used for line spacing.
*
* @see android.widget.TextView#setMinimumFontMetrics(Paint.FontMetrics)
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 5986238..3dd3a9e 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -24,6 +24,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Paint;
import android.graphics.RectF;
@@ -454,6 +455,35 @@
}
/**
+ * Set true for shifting the drawing x offset for showing overhang at the start position.
+ *
+ * This flag is ignored if the {@link #getUseBoundsForWidth()} is false.
+ *
+ * If this value is false, the Layout draws text from the zero even if there is a glyph
+ * stroke in a region where the x coordinate is negative.
+ *
+ * If this value is true, the Layout draws text with shifting the x coordinate of the
+ * drawing bounding box.
+ *
+ * This value is false by default.
+ *
+ * @param shiftDrawingOffsetForStartOverhang true for shifting the drawing offset for
+ * showing the stroke that is in the region where
+ * the x coordinate is negative.
+ * @see #setUseBoundsForWidth(boolean)
+ * @see #getUseBoundsForWidth()
+ */
+ @NonNull
+ // The corresponding getter is getShiftDrawingOffsetForStartOverhang()
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+ public Builder setShiftDrawingOffsetForStartOverhang(
+ boolean shiftDrawingOffsetForStartOverhang) {
+ mShiftDrawingOffsetForStartOverhang = shiftDrawingOffsetForStartOverhang;
+ return this;
+ }
+
+ /**
* Internal API that tells underlying line breaker that calculating bounding boxes even if
* the line break is performed with advances. This is useful for DynamicLayout internal
* implementation because it uses bounding box as well as advances.
@@ -566,6 +596,7 @@
private boolean mAddLastLineLineSpacing;
private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
private boolean mUseBoundsForWidth;
+ private boolean mShiftDrawingOffsetForStartOverhang;
private boolean mCalculateBounds;
@Nullable private Paint.FontMetrics mMinimumFontMetrics;
@@ -599,6 +630,7 @@
JUSTIFICATION_MODE_NONE,
null, // lineBreakConfig,
false, // useBoundsForWidth
+ false, // shiftDrawingOffsetForStartOverhang
null // minimumFontMetrics
);
@@ -677,7 +709,7 @@
b.mIncludePad, b.mFallbackLineSpacing, b.mEllipsizedWidth, b.mEllipsize,
b.mMaxLines, b.mBreakStrategy, b.mHyphenationFrequency, b.mLeftIndents,
b.mRightIndents, b.mJustificationMode, b.mLineBreakConfig, b.mUseBoundsForWidth,
- b.mMinimumFontMetrics);
+ b.mShiftDrawingOffsetForStartOverhang, b.mMinimumFontMetrics);
mColumns = columnSize;
if (b.mEllipsize != null) {
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index 9413f5c..5ec41591 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -202,38 +202,4 @@
throw new UnsupportedOperationException("The getInputTransferToken needs to be "
+ "implemented before making this call.");
}
-
- /**
- * Transfer the currently in progress touch gesture from the host to the requested
- * {@link SurfaceControlViewHost.SurfacePackage}. This requires that the
- * SurfaceControlViewHost was created with the current host's inputToken.
- * <p>
- * When the touch is transferred, the window currently receiving touch gets an ACTION_CANCEL
- * and does not receive any further input events for this gesture.
- * <p>
- * The transferred-to window receives an ACTION_DOWN event and then the remainder of the
- * input events for this gesture. It does not receive any of the previous events of this gesture
- * that the originating window received.
- * <p>
- * The "transferTouch" API only works for the current gesture. When a new gesture arrives,
- * input dispatcher will do a new round of hit testing. So, if the "host" window is still the
- * first thing that's being touched, then it will receive the new gesture again. It will
- * again be up to the host to transfer this new gesture to the embedded.
- * <p>
- * Once the transferred-to window receives the gesture, it can choose to give up this gesture
- * and send it to another window that it's linked to (it can't be an arbitrary window for
- * security reasons) using the same transferTouch API. Only the window currently receiving
- * touch is allowed to transfer the gesture.
- *
- * @param surfacePackage The SurfacePackage to transfer the gesture to.
- * @return Whether the touch stream was transferred.
- * @see SurfaceControlViewHost#transferTouchGestureToHost() for the reverse to transfer touch
- * gesture from the embedded to the host.
- */
- @FlaggedApi(Flags.FLAG_TRANSFER_GESTURE_TO_EMBEDDED)
- default boolean transferHostTouchGestureToEmbedded(
- @NonNull SurfaceControlViewHost.SurfacePackage surfacePackage) {
- throw new UnsupportedOperationException(
- "transferHostTouchGestureToEmbedded is unimplemented");
- }
}
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index eb28920..676b903 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -23,6 +23,9 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
+import android.text.TextUtils;
+import android.view.inputmethod.ConnectionlessHandwritingCallback;
+import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.Flags;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
@@ -225,15 +228,7 @@
}
startHandwriting(candidateView);
} else if (candidateView.getHandwritingDelegatorCallback() != null) {
- String delegatePackageName =
- candidateView.getAllowedHandwritingDelegatePackageName();
- if (delegatePackageName == null) {
- delegatePackageName = candidateView.getContext().getOpPackageName();
- }
- mImm.prepareStylusHandwritingDelegation(
- candidateView, delegatePackageName);
- candidateView.getHandwritingDelegatorCallback().run();
- mState.mHasPreparedHandwritingDelegation = true;
+ prepareDelegation(candidateView);
} else {
if (!mInitiateWithoutConnection) {
mState.mPendingConnectedView = new WeakReference<>(candidateView);
@@ -375,7 +370,7 @@
// A new view just gain focus. By default, we should show hover icon for it.
mShowHoverIconForConnectedView = true;
}
- if (!fromTouchEvent) {
+ if (!fromTouchEvent && view.isHandwritingDelegate()) {
tryAcceptStylusHandwritingDelegation(view);
}
return true;
@@ -393,15 +388,33 @@
}
}
+ private void prepareDelegation(View view) {
+ String delegatePackageName = view.getAllowedHandwritingDelegatePackageName();
+ if (delegatePackageName == null) {
+ delegatePackageName = view.getContext().getOpPackageName();
+ }
+ if (mImm.isConnectionlessStylusHandwritingAvailable()) {
+ // No other view should have focus during the connectionless handwriting session, as
+ // this could cause user confusion about the input target for the session.
+ view.getViewRootImpl().getView().clearFocus();
+ mImm.startConnectionlessStylusHandwritingForDelegation(
+ view, getCursorAnchorInfoForConnectionless(view), delegatePackageName,
+ view::post, new DelegationCallback(view, delegatePackageName));
+ mState.mHasInitiatedHandwriting = true;
+ mState.mShouldInitHandwriting = false;
+ } else {
+ mImm.prepareStylusHandwritingDelegation(view, delegatePackageName);
+ view.getHandwritingDelegatorCallback().run();
+ mState.mHasPreparedHandwritingDelegation = true;
+ }
+ }
+
/**
* Starts a stylus handwriting session for the delegate view, if {@link
* InputMethodManager#prepareStylusHandwritingDelegation} was previously called.
*/
@VisibleForTesting
public boolean tryAcceptStylusHandwritingDelegation(@NonNull View view) {
- if (!view.isHandwritingDelegate() || (mState != null && mState.mHasInitiatedHandwriting)) {
- return false;
- }
String delegatorPackageName =
view.getAllowedHandwritingDelegatorPackageName();
if (delegatorPackageName == null) {
@@ -807,6 +820,59 @@
&& view.shouldInitiateHandwriting();
}
+ private CursorAnchorInfo getCursorAnchorInfoForConnectionless(View view) {
+ CursorAnchorInfo.Builder builder = new CursorAnchorInfo.Builder();
+ // Fake editor views will usually display hint text. The hint text view can be used to
+ // populate the CursorAnchorInfo.
+ TextView textView = findFirstTextViewDescendent(view);
+ if (textView != null) {
+ textView.getCursorAnchorInfo(0, builder, mTempMatrix);
+ if (textView.getSelectionStart() < 0) {
+ // Insertion marker location is not populated if selection start is negative, so
+ // make a best guess.
+ float bottom = textView.getHeight() - textView.getExtendedPaddingBottom();
+ builder.setInsertionMarkerLocation(
+ /* horizontalPosition= */ textView.getCompoundPaddingStart(),
+ /* lineTop= */ textView.getExtendedPaddingTop(),
+ /* lineBaseline= */ bottom,
+ /* lineBottom= */ bottom,
+ /* flags= */ 0);
+ }
+ } else {
+ // If there is no TextView descendent, just populate the insertion marker with the start
+ // edge of the view.
+ mTempMatrix.reset();
+ view.transformMatrixToGlobal(mTempMatrix);
+ builder.setMatrix(mTempMatrix);
+ builder.setInsertionMarkerLocation(
+ /* horizontalPosition= */ view.isLayoutRtl() ? view.getWidth() : 0,
+ /* lineTop= */ 0,
+ /* lineBaseline= */ view.getHeight(),
+ /* lineBottom= */ view.getHeight(),
+ /* flags= */ 0);
+ }
+ return builder.build();
+ }
+
+ @Nullable
+ private static TextView findFirstTextViewDescendent(View view) {
+ if (view instanceof ViewGroup viewGroup) {
+ TextView textView;
+ for (int i = 0; i < viewGroup.getChildCount(); ++i) {
+ View child = viewGroup.getChildAt(i);
+ textView = (child instanceof TextView tv)
+ ? tv : findFirstTextViewDescendent(viewGroup.getChildAt(i));
+ if (textView != null
+ && textView.isAggregatedVisible()
+ && (!TextUtils.isEmpty(textView.getText())
+ || !TextUtils.isEmpty(textView.getHint()))) {
+ return textView;
+ }
+ }
+ }
+ return null;
+ }
+
/**
* A class used to track the handwriting areas set by the Views.
*
@@ -931,4 +997,35 @@
return true;
}
}
+
+ private class DelegationCallback implements ConnectionlessHandwritingCallback {
+ private final View mView;
+ private final String mDelegatePackageName;
+
+ private DelegationCallback(View view, String delegatePackageName) {
+ mView = view;
+ mDelegatePackageName = delegatePackageName;
+ }
+
+ @Override
+ public void onResult(@NonNull CharSequence text) {
+ mView.getHandwritingDelegatorCallback().run();
+ }
+
+ @Override
+ public void onError(int errorCode) {
+ switch (errorCode) {
+ case CONNECTIONLESS_HANDWRITING_ERROR_NO_TEXT_RECOGNIZED:
+ mView.getHandwritingDelegatorCallback().run();
+ break;
+ case CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED:
+ // Fall back to the old delegation flow
+ mImm.prepareStylusHandwritingDelegation(mView, mDelegatePackageName);
+ mView.getHandwritingDelegatorCallback().run();
+ mState.mHasInitiatedHandwriting = false;
+ mState.mHasPreparedHandwritingDelegation = true;
+ break;
+ }
+ }
+ }
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 29cc859..c475f6b 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -1098,4 +1098,7 @@
* (ie. not handled by any window which can handle the drag).
*/
void setUnhandledDragListener(IUnhandledDragListener listener);
+
+ boolean transferTouchGesture(in InputTransferToken transferFromToken,
+ in InputTransferToken transferToToken);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 55e49f8..d68a47c 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -370,11 +370,6 @@
*/
boolean cancelDraw(IWindow window);
- boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow);
-
- boolean transferHostTouchGestureToEmbedded(IWindow hostWindow,
- in InputTransferToken transferTouchToken);
-
/**
* Moves the focus to the adjacent window if there is one in the given direction. This can only
* move the focus to the window in the same leaf task.
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 1dd9cbb..06a923a 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -293,12 +293,12 @@
/**
* Gets an {@link InputTransferToken} which can be used to request focus on the embedded
* surface or to transfer touch gesture to the embedded surface.
- * @return the InputTransferToken associated with {@link SurfacePackage}
- * @see AttachedSurfaceControl#transferHostTouchGestureToEmbedded(SurfacePackage)
- *
- * @hide
+ * @return the InputTransferToken associated with {@link SurfacePackage} or {@code null} if
+ * the embedded hasn't set up its view or doesn't have input.
+ * @see WindowManager#transferTouchGesture(InputTransferToken, InputTransferToken)
*/
@Nullable
+ @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
public InputTransferToken getInputTransferToken() {
return mInputTransferToken;
}
@@ -577,9 +577,9 @@
}
/**
- * Transfer the currently in progress touch gesture to the parent
- * (if any) of this SurfaceControlViewHost. This requires that the
- * SurfaceControlViewHost was created with an associated hostInputToken.
+ * Transfer the currently in progress touch gesture to the parent (if any) of this
+ * SurfaceControlViewHost. This requires that the SurfaceControlViewHost was created with an
+ * associated host {@link InputTransferToken}.
*
* @return Whether the touch stream was transferred.
*/
@@ -587,13 +587,14 @@
if (mViewRoot == null) {
return false;
}
-
- final IWindowSession realWm = WindowManagerGlobal.getWindowSession();
- try {
- return realWm.transferEmbeddedTouchFocusToHost(mViewRoot.mWindow);
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
+ final WindowManager wm =
+ (WindowManager) mViewRoot.mContext.getSystemService(Context.WINDOW_SERVICE);
+ InputTransferToken embeddedToken = getInputTransferToken();
+ InputTransferToken hostToken = mWm.mHostInputTransferToken;
+ if (embeddedToken == null || hostToken == null) {
+ Log.w(TAG, "Failed to transferTouchGestureToHost. Host or embedded token is null");
+ return false;
}
- return false;
+ return wm.transferTouchGesture(getInputTransferToken(), mWm.mHostInputTransferToken);
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 25ade62..73b6ed6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5638,7 +5638,7 @@
private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
@FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
- public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = 0;
+ public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN;
@FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public static final float REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE = -1;
@FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
@@ -33457,7 +33457,6 @@
if (mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS) {
return FRAME_RATE_CATEGORY_NORMAL;
}
-
return mLastFrameRateCategory;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 657c8e6..9474a69 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -27,6 +27,8 @@
import static android.view.InsetsSource.ID_IME;
import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT;
+import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
+import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
import static android.view.View.PFLAG_DRAW_ANIMATION;
import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
@@ -1031,6 +1033,15 @@
private static final int FRAME_RATE_SETTING_REEVALUATE_TIME = 100;
/*
+ * The variables below are used to update frame rate category
+ */
+ private static final int FRAME_RATE_CATEGORY_COUNT = 5;
+ private int mFrameRateCategoryHighCount = 0;
+ private int mFrameRateCategoryHighHintCount = 0;
+ private int mFrameRateCategoryNormalCount = 0;
+ private int mFrameRateCategoryLowCount = 0;
+
+ /*
* the variables below are used to determine whther a dVRR feature should be enabled
*/
@@ -4084,7 +4095,14 @@
// when the values are applicable.
setPreferredFrameRate(mPreferredFrameRate);
setPreferredFrameRateCategory(mPreferredFrameRateCategory);
+ mFrameRateCategoryHighCount = mFrameRateCategoryHighCount > 0
+ ? mFrameRateCategoryHighCount - 1 : mFrameRateCategoryHighCount;
+ mFrameRateCategoryNormalCount = mFrameRateCategoryNormalCount > 0
+ ? mFrameRateCategoryNormalCount - 1 : mFrameRateCategoryNormalCount;
+ mFrameRateCategoryLowCount = mFrameRateCategoryLowCount > 0
+ ? mFrameRateCategoryLowCount - 1 : mFrameRateCategoryLowCount;
mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
+ mPreferredFrameRate = -1;
}
private void createSyncIfNeeded() {
@@ -12296,7 +12314,8 @@
}
try {
- if (mLastPreferredFrameRate != preferredFrameRate) {
+ if (mLastPreferredFrameRate != preferredFrameRate
+ && preferredFrameRate >= 0) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(
Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate "
@@ -12346,7 +12365,25 @@
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
public void votePreferredFrameRateCategory(int frameRateCategory) {
- mPreferredFrameRateCategory = Math.max(mPreferredFrameRateCategory, frameRateCategory);
+ if (frameRateCategory == FRAME_RATE_CATEGORY_HIGH) {
+ mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
+ } else if (frameRateCategory == FRAME_RATE_CATEGORY_HIGH_HINT) {
+ mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT;
+ } else if (frameRateCategory == FRAME_RATE_CATEGORY_NORMAL) {
+ mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT;
+ } else if (frameRateCategory == FRAME_RATE_CATEGORY_LOW) {
+ mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT;
+ }
+
+ if (mFrameRateCategoryHighCount > 0) {
+ mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
+ } else if (mFrameRateCategoryHighHintCount > 0) {
+ mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT;
+ } else if (mFrameRateCategoryNormalCount > 0) {
+ mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NORMAL;
+ } else if (mFrameRateCategoryLowCount > 0) {
+ mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW;
+ }
mHasInvalidation = true;
}
@@ -12368,13 +12405,7 @@
return;
}
- if (mPreferredFrameRate == 0) {
- mPreferredFrameRate = frameRate;
- } else if (frameRate > 60 || mPreferredFrameRate > 60) {
- mPreferredFrameRate = Math.max(mPreferredFrameRate, frameRate);
- } else if (mPreferredFrameRate != frameRate) {
- mPreferredFrameRate = 60;
- }
+ mPreferredFrameRate = Math.max(mPreferredFrameRate, frameRate);
mHasInvalidation = true;
mHandler.removeMessages(MSG_FRAME_RATE_SETTING);
@@ -12403,7 +12434,7 @@
*/
@VisibleForTesting
public float getPreferredFrameRate() {
- return mPreferredFrameRate;
+ return mPreferredFrameRate >= 0 ? mPreferredFrameRate : mLastPreferredFrameRate;
}
/**
@@ -12431,19 +12462,6 @@
boostTimeOut);
}
- @Override
- public boolean transferHostTouchGestureToEmbedded(
- @NonNull SurfaceControlViewHost.SurfacePackage surfacePackage) {
- final IWindowSession realWm = WindowManagerGlobal.getWindowSession();
- try {
- return realWm.transferHostTouchGestureToEmbedded(mWindow,
- surfacePackage.getInputTransferToken());
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
- }
- return false;
- }
-
/**
* Set the default back key callback for windowless window, to forward the back key event
* to host app.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0302a0d..4e13878 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1548,6 +1548,48 @@
"android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI";
/**
+ * Application or Activity level
+ * {@link android.content.pm.PackageManager.Property PackageManager.Property} to provide any
+ * preferences for showing all or specific Activities on small cover displays of foldable
+ * style devices.
+ *
+ * <p>The only supported value for the property is {@link #COMPAT_SMALL_COVER_SCREEN_OPT_IN}.
+ *
+ * <p><b>Syntax:</b>
+ * <pre>
+ * <application>
+ * <property
+ * android:name="android.window.PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN"
+ * android:value=1 <!-- COMPAT_COVER_SCREEN_OPT_IN -->/>
+ * </application>
+ * </pre>
+ */
+ @FlaggedApi(Flags.FLAG_COVER_DISPLAY_OPT_IN)
+ String PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN =
+ "android.window.PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN";
+
+ /**
+ * Value applicable for the {@link #PROPERTY_COMPAT_ALLOW_SMALL_COVER_SCREEN} property to
+ * provide a signal to the system that an application or its specific activities explicitly
+ * opt into being displayed on small foldable device cover screens that measure at least 1.5
+ * inches for the shorter dimension and at least 2.4 inches for the longer dimension.
+ */
+ @CompatSmallScreenPolicy
+ @FlaggedApi(Flags.FLAG_COVER_DISPLAY_OPT_IN)
+ int COMPAT_SMALL_COVER_SCREEN_OPT_IN = 1;
+
+ /**
+ * @hide
+ */
+ @IntDef({
+ COMPAT_SMALL_COVER_SCREEN_OPT_IN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface CompatSmallScreenPolicy {}
+
+
+
+ /**
* Request for app's keyboard shortcuts to be retrieved asynchronously.
*
* @param receiver The callback to be triggered when the result is ready.
@@ -6196,6 +6238,54 @@
}
/**
+ * Transfer the currently in progress touch gesture from the transferFromToken to the
+ * transferToToken.
+ * <p><br>
+ * This requires that the fromToken and toToken are associated with each other. The association
+ * can be done by creating a {@link SurfaceControlViewHost} and passing the host's
+ * {@link InputTransferToken} for
+ * {@link SurfaceControlViewHost#SurfaceControlViewHost(Context, Display, InputTransferToken)}.
+ * <p>
+ * The host is likely to be an {@link AttachedSurfaceControl} so the host token can be
+ * retrieved via {@link AttachedSurfaceControl#getInputTransferToken()}.
+ * <p><br>
+ * Only the window currently receiving touch is allowed to transfer the gesture so if the caller
+ * attempts to transfer touch gesture from a token that doesn't have touch, it will fail the
+ * transfer.
+ * <p><br>
+ * When the host wants to transfer touch gesture to the embedded, it can retrieve the embedded
+ * token via {@link SurfaceControlViewHost.SurfacePackage#getInputTransferToken()} and pass its
+ * own token as the transferFromToken.
+ * <p>
+ * When the embedded wants to transfer touch gesture to the host, it can pass in its own token
+ * as the transferFromToken and use the associated host's {@link InputTransferToken} as the
+ * transferToToken
+ * <p><br>
+ * When the touch is transferred, the window currently receiving touch gets an ACTION_CANCEL
+ * and does not receive any further input events for this gesture.
+ * <p>
+ * The transferred-to window receives an ACTION_DOWN event and then the remainder of the input
+ * events for this gesture. It does not receive any of the previous events of this gesture that
+ * the originating window received.
+ * <p>
+ * The transferTouchGesture API only works for the current gesture. When a new gesture arrives,
+ * input dispatcher will do a new round of hit testing. So, if the host window is still the
+ * first thing that's being touched, then it will receive the new gesture again. It will again
+ * be up to the host to transfer this new gesture to the embedded.
+ *
+ * @param transferFromToken the InputTransferToken for the currently active gesture
+ * @param transferToToken the InputTransferToken to transfer the gesture to.
+ * @return Whether the touch stream was transferred.
+ * @see android.view.SurfaceControlViewHost.SurfacePackage#getInputTransferToken()
+ * @see AttachedSurfaceControl#getInputTransferToken()
+ */
+ @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
+ default boolean transferTouchGesture(@NonNull InputTransferToken transferFromToken,
+ @NonNull InputTransferToken transferToToken) {
+ throw new UnsupportedOperationException("transferTouchGesture is not implemented");
+ }
+
+ /**
* @hide
*/
default @NonNull IBinder getDefaultToken() {
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 1428963..2c98d9a 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -930,6 +930,17 @@
return surfaceControlInputReceiverInfo.mClientToken;
}
+ boolean transferTouchGesture(InputTransferToken transferFromToken,
+ InputTransferToken transferToToken) {
+ try {
+ return getWindowManagerService().transferTouchGesture(transferFromToken,
+ transferToToken);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ return false;
+ }
+
private final class TrustedPresentationListener extends
ITrustedPresentationListener.Stub {
private static int sId = 0;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 1e3d062..44e2493 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -563,6 +563,14 @@
}
@Override
+ public boolean transferTouchGesture(@NonNull InputTransferToken transferFromToken,
+ @NonNull InputTransferToken transferToToken) {
+ Objects.requireNonNull(transferFromToken);
+ Objects.requireNonNull(transferToToken);
+ return mGlobal.transferTouchGesture(transferFromToken, transferToToken);
+ }
+
+ @Override
public @ScreenRecordingState int addScreenRecordingCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<@ScreenRecordingState Integer> callback) {
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 3f1ae51..2b2c507 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -651,21 +651,6 @@
}
@Override
- public boolean transferEmbeddedTouchFocusToHost(IWindow window) {
- Log.e(TAG, "Received request to transferEmbeddedTouch focus on WindowlessWindowManager" +
- " we shouldn't get here!");
- return false;
- }
-
- @Override
- public boolean transferHostTouchGestureToEmbedded(IWindow hostWindow,
- InputTransferToken embeddedInputToken) {
- Log.e(TAG, "Received request to transferHostTouchGestureToEmbedded on"
- + " WindowlessWindowManager. We shouldn't get here!");
- return false;
- }
-
- @Override
public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) {
Log.e(TAG, "Received request to moveFocusToAdjacentWindow on"
+ " WindowlessWindowManager. We shouldn't get here!");
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 57e4e6a..9847cb1 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -181,6 +181,7 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewDebug;
+import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewHierarchyEncoder;
import android.view.ViewParent;
@@ -866,6 +867,7 @@
private final boolean mUseTextPaddingForUiTranslation;
private boolean mUseBoundsForWidth;
+ private boolean mShiftDrawingOffsetForStartOverhang;
@Nullable private Paint.FontMetrics mMinimumFontMetrics;
@Nullable private Paint.FontMetrics mLocalePreferredFontMetrics;
private boolean mUseLocalePreferredLineHeightForMinimum;
@@ -1621,6 +1623,10 @@
hasUseBoundForWidthValue = true;
break;
case com.android.internal.R.styleable
+ .TextView_shiftDrawingOffsetForStartOverhang:
+ mShiftDrawingOffsetForStartOverhang = a.getBoolean(attr, false);
+ break;
+ case com.android.internal.R.styleable
.TextView_useLocalePreferredLineHeightForMinimum:
mUseLocalePreferredLineHeightForMinimum = a.getBoolean(attr, false);
break;
@@ -4922,6 +4928,8 @@
* @param useBoundsForWidth true for using bounding box for width. false for using advances for
* width.
* @see #getUseBoundsForWidth()
+ * @see #setShiftDrawingOffsetForStartOverhang(boolean)
+ * @see #getShiftDrawingOffsetForStartOverhang()
*/
@FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
public void setUseBoundsForWidth(boolean useBoundsForWidth) {
@@ -4939,6 +4947,8 @@
* Returns true if using bounding box as a width, false for using advance as a width.
*
* @see #setUseBoundsForWidth(boolean)
+ * @see #setShiftDrawingOffsetForStartOverhang(boolean)
+ * @see #getShiftDrawingOffsetForStartOverhang()
* @return True if using bounding box for width, false if using advance for width.
*/
@FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
@@ -4947,6 +4957,53 @@
}
/**
+ * Set true for shifting the drawing x offset for showing overhang at the start position.
+ *
+ * This flag is ignored if the {@link #getUseBoundsForWidth()} is false.
+ *
+ * If this value is false, the TextView draws text from the zero even if there is a glyph stroke
+ * in a region where the x coordinate is negative. TextView clips the stroke in the region where
+ * the X coordinate is negative unless the parents has {@link ViewGroup#getClipChildren()} to
+ * true. This is useful for aligning multiple TextViews vertically.
+ *
+ * If this value is true, the TextView draws text with shifting the x coordinate of the drawing
+ * bounding box. This prevents the clipping even if the parents doesn't have
+ * {@link ViewGroup#getClipChildren()} to true.
+ *
+ * This value is false by default.
+ *
+ * @param shiftDrawingOffsetForStartOverhang true for shifting the drawing offset for showing
+ * the stroke that is in the region whre the x
+ * coorinate is negative.
+ * @see #setUseBoundsForWidth(boolean)
+ * @see #getUseBoundsForWidth()
+ */
+ @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+ public void setShiftDrawingOffsetForStartOverhang(boolean shiftDrawingOffsetForStartOverhang) {
+ if (mShiftDrawingOffsetForStartOverhang != shiftDrawingOffsetForStartOverhang) {
+ mShiftDrawingOffsetForStartOverhang = shiftDrawingOffsetForStartOverhang;
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
+ }
+ }
+
+ /**
+ * Returns true if shifting the drawing x offset for start overhang.
+ *
+ * @see #setShiftDrawingOffsetForStartOverhang(boolean)
+ * @see #setUseBoundsForWidth(boolean)
+ * @see #getUseBoundsForWidth()
+ * @return True if shifting the drawing x offset for start overhang.
+ */
+ @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
+ public boolean getShiftDrawingOffsetForStartOverhang() {
+ return mShiftDrawingOffsetForStartOverhang;
+ }
+
+ /**
* Set the minimum font metrics used for line spacing.
*
* <p>
@@ -11001,6 +11058,7 @@
null,
boring,
mUseBoundsForWidth,
+ mShiftDrawingOffsetForStartOverhang,
getResolvedMinimumFontMetrics());
}
@@ -11028,6 +11086,7 @@
effectiveEllipsize,
boring,
mUseBoundsForWidth,
+ mShiftDrawingOffsetForStartOverhang,
getResolvedMinimumFontMetrics());
}
}
diff --git a/core/java/android/window/InputTransferToken.java b/core/java/android/window/InputTransferToken.java
index bed0e0e..f1b37bf 100644
--- a/core/java/android/window/InputTransferToken.java
+++ b/core/java/android/window/InputTransferToken.java
@@ -31,6 +31,11 @@
/**
* A token that can be used to request focus on or to transfer touch gesture to a
* {@link SurfaceControlViewHost} or {@link android.view.SurfaceControl} that has an input channel.
+ * <p>
+ * For {@link SurfaceControlViewHost}, the token can be retrieved via
+ * {@link SurfaceControlViewHost.SurfacePackage#getInputTransferToken()}
+ *
+ * @see android.view.WindowManager#transferTouchGesture(InputTransferToken, InputTransferToken)
*/
@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
public final class InputTransferToken implements Parcelable {
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 3ffa274..8b3bd97 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -20,13 +20,6 @@
flag {
namespace: "window_surfaces"
- name: "transfer_gesture_to_embedded"
- description: "Enable public API for Window Surfaces"
- bug: "287076178"
-}
-
-flag {
- namespace: "window_surfaces"
name: "delete_capture_display"
description: "Delete uses of ScreenCapture#captureDisplay"
is_fixed_read_only: true
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index bc63881..ce74848 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -69,4 +69,12 @@
name: "embedded_activity_back_nav_flag"
description: "Refines embedded activity back navigation behavior"
bug: "293642394"
+}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "cover_display_opt_in"
+ description: "Properties to allow apps and activities to opt-in to cover display rendering"
+ bug: "312530526"
+ is_fixed_read_only: true
}
\ No newline at end of file
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index d433ca3..73df5e8 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -408,6 +408,7 @@
// Derived fields
private long mLongVersionCode;
private int mLocaleConfigRes;
+ private boolean mAllowCrossUidActivitySwitchFromBelow;
private List<AndroidPackageSplit> mSplits;
@@ -1542,6 +1543,11 @@
}
@Override
+ public boolean isAllowCrossUidActivitySwitchFromBelow() {
+ return mAllowCrossUidActivitySwitchFromBelow;
+ }
+
+ @Override
public boolean hasPreserveLegacyExternalStorage() {
return getBoolean(Booleans.PRESERVE_LEGACY_EXTERNAL_STORAGE);
}
@@ -2199,6 +2205,12 @@
}
@Override
+ public ParsingPackage setAllowCrossUidActivitySwitchFromBelow(boolean value) {
+ mAllowCrossUidActivitySwitchFromBelow = value;
+ return this;
+ }
+
+ @Override
public PackageImpl setResourceOverlay(boolean value) {
return setBoolean(Booleans.OVERLAY, value);
}
@@ -2656,6 +2668,7 @@
if (!mKnownActivityEmbeddingCerts.isEmpty()) {
appInfo.setKnownActivityEmbeddingCerts(mKnownActivityEmbeddingCerts);
}
+ appInfo.allowCrossUidActivitySwitchFromBelow = mAllowCrossUidActivitySwitchFromBelow;
return appInfo;
}
@@ -3250,6 +3263,7 @@
dest.writeInt(this.uid);
dest.writeLong(this.mBooleans);
dest.writeLong(this.mBooleans2);
+ dest.writeBoolean(this.mAllowCrossUidActivitySwitchFromBelow);
}
public PackageImpl(Parcel in) {
@@ -3411,6 +3425,7 @@
this.uid = in.readInt();
this.mBooleans = in.readLong();
this.mBooleans2 = in.readLong();
+ this.mAllowCrossUidActivitySwitchFromBelow = in.readBoolean();
assignDerivedFields();
assignDerivedFields2();
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
index ef106e0..5d185af 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
@@ -374,6 +374,9 @@
ParsingPackage setZygotePreloadName(String zygotePreloadName);
+ ParsingPackage setAllowCrossUidActivitySwitchFromBelow(
+ boolean allowCrossUidActivitySwitchFromBelow);
+
ParsingPackage sortActivities();
ParsingPackage sortReceivers();
@@ -518,6 +521,8 @@
@Nullable
String getZygotePreloadName();
+ boolean isAllowCrossUidActivitySwitchFromBelow();
+
boolean isBackupAllowed();
boolean isTaskReparentingAllowed();
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index e0fdbc6..2e6053d 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -2374,8 +2374,10 @@
.setRestrictedAccountType(string(R.styleable.AndroidManifestApplication_restrictedAccountType, sa))
.setZygotePreloadName(string(R.styleable.AndroidManifestApplication_zygotePreloadName, sa))
// Non-Config String
- .setPermission(nonConfigString(0, R.styleable.AndroidManifestApplication_permission, sa));
- // CHECKSTYLE:on
+ .setPermission(nonConfigString(0, R.styleable.AndroidManifestApplication_permission, sa))
+ .setAllowCrossUidActivitySwitchFromBelow(bool(true, R.styleable.AndroidManifestApplication_allowCrossUidActivitySwitchFromBelow, sa));
+
+ // CHECKSTYLE:on
//@formatter:on
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b5b3a48..e46b8d7 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1615,7 +1615,8 @@
STRONG_AUTH_REQUIRED_AFTER_TIMEOUT,
STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN,
STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT,
- SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED})
+ SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED,
+ SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST})
@Retention(RetentionPolicy.SOURCE)
public @interface StrongAuthFlags {}
@@ -1641,7 +1642,8 @@
/**
* Strong authentication is required because the user has been locked out after too many
- * attempts.
+ * attempts using primary auth methods (i.e. PIN/pattern/password) from the lock screen,
+ * Android Settings, and BiometricPrompt where user authentication is required.
*/
public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
@@ -1674,12 +1676,23 @@
public static final int SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED = 0x100;
/**
+ * Some authentication is required because adaptive auth has requested to lock device due to
+ * repeated failed primary auth (i.e. PIN/pattern/password) or biometric auth attempts which
+ * can come from Android Settings or BiometricPrompt where user authentication is required,
+ * in addition to from the lock screen. When a risk is determined, adaptive auth will
+ * proactively prompt the lock screen and will require users to re-enter the device with
+ * either primary auth or biometric auth (if not prohibited by other flags).
+ */
+ public static final int SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST = 0x200;
+
+ /**
* Strong auth flags that do not prevent biometric methods from being accepted as auth.
* If any other flags are set, biometric authentication is disabled.
*/
private static final int ALLOWING_BIOMETRIC = STRONG_AUTH_NOT_REQUIRED
| SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
- | SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED;
+ | SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED
+ | SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
private final H mHandler;
diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java
index 096f246..d430fe3 100644
--- a/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -1507,4 +1507,11 @@
* @hide
*/
boolean isVisibleToInstantApps();
+
+ /**
+ * @see ApplicationInfo#allowCrossUidActivitySwitchFromBelow
+ * @see R.styleable#AndroidManifestApplication_allowCrossUidActivitySwitchFromBelow
+ * @hide
+ */
+ boolean isAllowCrossUidActivitySwitchFromBelow();
}
diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto
index b9905e8..b7408a4 100644
--- a/core/proto/android/content/package_item_info.proto
+++ b/core/proto/android/content/package_item_info.proto
@@ -113,6 +113,7 @@
optional int32 enable_gwp_asan = 19;
optional int32 enable_memtag = 20;
optional bool native_heap_zero_init = 21;
+ optional bool allow_cross_uid_activity_switch_from_below = 22;
}
optional Detail detail = 17;
repeated string overlay_paths = 18;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e7df19c..4131644 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3793,6 +3793,14 @@
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK"
android:protectionLevel="internal|role" />
+ <!-- Allows an application to manage policy related to theft detection.
+ @FlaggedApi("android.app.admin.flags.device_theft_api_enabled")
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_THEFT_DETECTION"
+ android:protectionLevel="internal|role" />
+
<!-- Allows an application to manage policy related to system apps.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
@@ -3830,6 +3838,24 @@
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS"
android:protectionLevel="internal|role" />
+ <!-- Allows an application to manage policy related to block package uninstallation.
+ @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy related to camera toggle.
+ @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE"
+ android:protectionLevel="internal|role" />
+
+ <!-- Allows an application to manage policy related to microphone toggle.
+ @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE"
+ android:protectionLevel="internal|role" />
+
<!-- Allows an application to set device policies outside the current user
that are critical for securing data within the current user.
<p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
@@ -6884,13 +6910,10 @@
<permission android:name="android.permission.ACCESS_DRM_CERTIFICATES"
android:protectionLevel="signature|privileged" />
- <!-- Allows an application to manage media projection sessions, by showing the permission dialog
- to the user and creating a new token for each capture session.
- @FlaggedApi("com.android.media.flags.limit_manage_media_projection")
- @SystemApi Only granted to apps holding role SYSTEM_UI.
+ <!-- Api Allows an application to manage media projection sessions.
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"
- android:protectionLevel="internal|role" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to read install sessions
@hide This is not a third-party API (intended for system apps). -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4ee03de..cc6460e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5891,6 +5891,17 @@
use glyph bound's as a source of text width. -->
<!-- @FlaggedApi("com.android.text.flags.use_bounds_for_width") -->
<attr name="useBoundsForWidth" format="boolean" />
+
+
+ <!-- Whether to shift the drawing offset for prevent clipping start drawing offset.
+ This value is ignored when the useBoundsForWidth attribute is false.
+
+ If this value is false, the TextView draws text from the zero X coordinate. This is
+ useful for aligning multiple TextViews vertically.
+ If this value is true, the TextView shift the drawing offset not to clip the
+ stroke in the region where the X coordinate is negative. -->
+ <!-- @FlaggedApi("com.android.text.flags.use_bounds_for_width") -->
+ <attr name="shiftDrawingOffsetForStartOverhang" format="boolean" />
<!-- Whether to use the locale preferred line height for the minimum line height.
This flag is useful for preventing jitter of entering letters into empty EditText.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 734ff8d..b2e0be7c 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1919,6 +1919,12 @@
try to load its code when launching components. The default is true
for normal behavior. -->
<attr name="hasCode" format="boolean" />
+ <!-- Specifies if activities can be launched on top of this application by activities from
+ other applications in the same task. If set to false, activity launches which would
+ replace this application with another when in the user's view will be blocked.
+ The default is true. -->
+ <!-- @FlaggedApi("android.security.asm_restrictions_enabled") -->
+ <attr name="allowCrossUidActivitySwitchFromBelow" format="boolean" />
<attr name="persistent" />
<attr name="persistentWhenFeatureAvailable" />
<attr name="requiredForAllUsers" />
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index dcb6bb0..8af8cb8 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -159,6 +159,12 @@
<public name="contentSensitivity" />
<!-- @FlaggedApi("android.view.inputmethod.connectionless_handwriting") -->
<public name="supportsConnectionlessStylusHandwriting" />
+ <!-- @FlaggedApi("android.nfc.Flags.FLAG_OBSERVE_MODE") -->
+ <public name="defaultToObserveMode"/>
+ <!-- @FlaggedApi("android.security.asm_restrictions_enabled") -->
+ <public name="allowCrossUidActivitySwitchFromBelow"/>
+ <!-- @FlaggedApi("com.android.text.flags.use_bounds_for_width") -->
+ <public name="shiftDrawingOffsetForStartOverhang" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01bc0000">
diff --git a/core/tests/BroadcastRadioTests/TEST_MAPPING b/core/tests/BroadcastRadioTests/TEST_MAPPING
index b085a27..5637063 100644
--- a/core/tests/BroadcastRadioTests/TEST_MAPPING
+++ b/core/tests/BroadcastRadioTests/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "postsubmit": [
+ "presubmit": [
{
"name": "BroadcastRadioTests"
}
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 2327b20..48ef7e6 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -40,6 +40,7 @@
import android.app.Application;
import android.app.IApplicationThread;
import android.app.PictureInPictureParams;
+import android.app.PictureInPictureUiState;
import android.app.ResourcesManager;
import android.app.servertransaction.ActivityConfigurationChangeItem;
import android.app.servertransaction.ActivityLifecycleItem;
@@ -706,6 +707,9 @@
final TestActivity activity = mActivityTestRule.launchActivity(startIntent);
final ActivityThread activityThread = activity.getActivityThread();
final ActivityClientRecord r = getActivityClientRecord(activity);
+ if (android.app.Flags.enablePipUiStateCallbackOnEntering()) {
+ activity.mPipUiStateLatch = new CountDownLatch(1);
+ }
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
activityThread.handlePictureInPictureRequested(r);
@@ -940,6 +944,11 @@
* latch reaches 0.
*/
volatile CountDownLatch mConfigLatch;
+ /**
+ * A latch used to notify tests that we're about to wait for the
+ * onPictureInPictureUiStateChanged callback.
+ */
+ volatile CountDownLatch mPipUiStateLatch;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -974,6 +983,14 @@
if (getIntent().getBooleanExtra(PIP_REQUESTED_OVERRIDE_ENTER, false)) {
enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
mPipEntered = true;
+ // Await for onPictureInPictureUiStateChanged callback if applicable
+ if (mPipUiStateLatch != null) {
+ try {
+ mPipUiStateLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
+ }
return true;
} else if (getIntent().getBooleanExtra(PIP_REQUESTED_OVERRIDE_SKIP, false)) {
mPipEnterSkipped = true;
@@ -982,6 +999,13 @@
return super.onPictureInPictureRequested();
}
+ @Override
+ public void onPictureInPictureUiStateChanged(PictureInPictureUiState pipState) {
+ if (mPipUiStateLatch != null && pipState.isEnteringPip()) {
+ mPipUiStateLatch.countDown();
+ }
+ }
+
boolean pipRequested() {
return mPipRequested;
}
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 0657e4b..433d353 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -660,10 +660,22 @@
public void votePreferredFrameRate_voteFrameRateCategory_aggregate() {
View view = new View(sContext);
attachViewToWindow(view);
+ ViewRootImpl viewRootImpl = view.getViewRootImpl();
sInstrumentation.runOnMainSync(() -> {
- ViewRootImpl viewRootImpl = view.getViewRootImpl();
assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ });
+
+ // reset the frame rate category counts
+ for (int i = 0; i < 5; i++) {
+ sInstrumentation.runOnMainSync(() -> {
+ view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ view.invalidate();
+ });
+ sInstrumentation.waitForIdleSync();
+ }
+
+ sInstrumentation.runOnMainSync(() -> {
viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_LOW);
assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW);
viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_NORMAL);
@@ -699,6 +711,8 @@
viewRootImpl.votePreferredFrameRate(24);
assertEquals(viewRootImpl.getPreferredFrameRate(), 24, 0.1);
viewRootImpl.votePreferredFrameRate(30);
+ assertEquals(viewRootImpl.getPreferredFrameRate(), 30, 0.1);
+ viewRootImpl.votePreferredFrameRate(60);
assertEquals(viewRootImpl.getPreferredFrameRate(), 60, 0.1);
viewRootImpl.votePreferredFrameRate(120);
assertEquals(viewRootImpl.getPreferredFrameRate(), 120, 0.1);
@@ -721,6 +735,18 @@
sInstrumentation.runOnMainSync(() -> {
assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ });
+
+ // reset the frame rate category counts
+ for (int i = 0; i < 5; i++) {
+ sInstrumentation.runOnMainSync(() -> {
+ view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ view.invalidate();
+ });
+ sInstrumentation.waitForIdleSync();
+ }
+
+ sInstrumentation.runOnMainSync(() -> {
view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_LOW);
view.invalidate();
assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW);
@@ -847,7 +873,18 @@
assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
FRAME_RATE_CATEGORY_NO_PREFERENCE);
assertEquals(viewRootImpl.getPreferredFrameRate(), frameRate, 0.1);
+ });
+ // reset the frame rate category counts
+ for (int i = 0; i < 5; i++) {
+ sInstrumentation.runOnMainSync(() -> {
+ view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ view.invalidate();
+ });
+ sInstrumentation.waitForIdleSync();
+ }
+
+ sInstrumentation.runOnMainSync(() -> {
view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_LOW);
view.invalidate();
assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW);
@@ -882,18 +919,6 @@
ViewRootImpl viewRootImpl = view.getViewRootImpl();
- // Frequent update
- sInstrumentation.runOnMainSync(() -> {
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
- FRAME_RATE_CATEGORY_NO_PREFERENCE);
- view.invalidate();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
- view.invalidate();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
- view.invalidate();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
- });
-
// In transistion from frequent update to infrequent update
Thread.sleep(delay);
sInstrumentation.runOnMainSync(() -> {
@@ -901,9 +926,28 @@
assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
});
+ // reset the frame rate category counts
+ for (int i = 0; i < 5; i++) {
+ sInstrumentation.runOnMainSync(() -> {
+ view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ view.invalidate();
+ });
+ sInstrumentation.waitForIdleSync();
+ }
+
+ // In transistion from frequent update to infrequent update
+ Thread.sleep(delay);
+ sInstrumentation.runOnMainSync(() -> {
+ view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ view.invalidate();
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+ FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ });
+
// Infrequent update
Thread.sleep(delay);
sInstrumentation.runOnMainSync(() -> {
+ view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT);
view.invalidate();
assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_NORMAL);
});
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
index 396d403..fb5e512 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
@@ -16,8 +16,8 @@
package android.hardware.devicestate;
-import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
+import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE_IDENTIFIER;
+import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE_IDENTIFIER;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
@@ -39,18 +39,18 @@
public final class DeviceStateTest {
@Test
public void testConstruct() {
- final DeviceState state = new DeviceState(MINIMUM_DEVICE_STATE /* identifier */,
+ final DeviceState state = new DeviceState(MINIMUM_DEVICE_STATE_IDENTIFIER /* identifier */,
"TEST_CLOSED" /* name */, DeviceState.FLAG_CANCEL_OVERRIDE_REQUESTS /* flags */);
- assertEquals(state.getIdentifier(), MINIMUM_DEVICE_STATE);
+ assertEquals(state.getIdentifier(), MINIMUM_DEVICE_STATE_IDENTIFIER);
assertEquals(state.getName(), "TEST_CLOSED");
assertEquals(state.getFlags(), DeviceState.FLAG_CANCEL_OVERRIDE_REQUESTS);
}
@Test
public void testConstruct_nullName() {
- final DeviceState state = new DeviceState(MAXIMUM_DEVICE_STATE /* identifier */,
+ final DeviceState state = new DeviceState(MAXIMUM_DEVICE_STATE_IDENTIFIER /* identifier */,
null /* name */, 0/* flags */);
- assertEquals(state.getIdentifier(), MAXIMUM_DEVICE_STATE);
+ assertEquals(state.getIdentifier(), MAXIMUM_DEVICE_STATE_IDENTIFIER);
assertNull(state.getName());
assertEquals(state.getFlags(), 0);
}
@@ -58,7 +58,8 @@
@Test
public void testConstruct_tooLargeIdentifier() {
assertThrows(IllegalArgumentException.class, () -> {
- final DeviceState state = new DeviceState(MAXIMUM_DEVICE_STATE + 1 /* identifier */,
+ final DeviceState state = new DeviceState(
+ MAXIMUM_DEVICE_STATE_IDENTIFIER + 1 /* identifier */,
null /* name */, 0 /* flags */);
});
}
@@ -66,7 +67,8 @@
@Test
public void testConstruct_tooSmallIdentifier() {
assertThrows(IllegalArgumentException.class, () -> {
- final DeviceState state = new DeviceState(MINIMUM_DEVICE_STATE - 1 /* identifier */,
+ final DeviceState state = new DeviceState(
+ MINIMUM_DEVICE_STATE_IDENTIFIER - 1 /* identifier */,
null /* name */, 0 /* flags */);
});
}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index c8cbb98..42e3387 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2077,6 +2077,12 @@
"group": "WM_DEBUG_LOCKTASK",
"at": "com\/android\/server\/wm\/LockTaskController.java"
},
+ "-315778658": {
+ "message": "transferTouchGesture failed because args transferFromToken or transferToToken is null",
+ "level": "ERROR",
+ "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"-312353598": {
"message": "Executing finish of activity: %s",
"level": "VERBOSE",
@@ -2293,12 +2299,6 @@
"group": "WM_DEBUG_ANIM",
"at": "com\/android\/server\/wm\/WindowState.java"
},
- "-90559682": {
- "message": "Config is skipping already pausing %s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_CONFIGURATION",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"-87705714": {
"message": "findFocusedWindow: focusedApp=null using new focus @ %s",
"level": "VERBOSE",
@@ -3547,12 +3547,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "1011462000": {
- "message": "Re-launching after pause: %s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_STATES",
- "at": "com\/android\/server\/wm\/TaskFragment.java"
- },
"1015746067": {
"message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s",
"level": "VERBOSE",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index dffcc6d..b5ea1b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -24,6 +24,7 @@
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
import static android.view.WindowManager.TRANSIT_SLEEP;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static com.android.wm.shell.util.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
@@ -929,7 +930,14 @@
Slog.e(TAG, "Duplicate call to finish");
return;
}
- if (!toHome) {
+
+ boolean returningToApp = !toHome
+ && !mWillFinishToHome
+ && mPausingTasks != null
+ && mState == STATE_NORMAL;
+ if (returningToApp && allAppsAreTranslucent(mPausingTasks)) {
+ mHomeTransitionObserver.notifyHomeVisibilityChanged(true);
+ } else if (!toHome) {
// For some transitions, we may have notified home activity that it became visible.
// We need to notify the observer that we are no longer going home.
mHomeTransitionObserver.notifyHomeVisibilityChanged(false);
@@ -948,7 +956,7 @@
if (toHome) wct.reorder(mRecentsTask, true /* toTop */);
else wct.restoreTransientOrder(mRecentsTask);
}
- if (!toHome && !mWillFinishToHome && mPausingTasks != null && mState == STATE_NORMAL) {
+ if (returningToApp) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, " returning to app");
// The gesture is returning to the pausing-task(s) rather than continuing with
// recents, so end the transition by moving the app back to the top (and also
@@ -1048,6 +1056,18 @@
}
}
+ private boolean allAppsAreTranslucent(ArrayList<TaskState> tasks) {
+ if (tasks == null || tasks.isEmpty()) {
+ return false;
+ }
+ for (int i = tasks.size() - 1; i >= 0; --i) {
+ if (!tasks.get(i).mIsTranslucent) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private void cleanUpPausingOrClosingTask(TaskState task, WindowContainerTransaction wct,
SurfaceControl.Transaction finishTransaction, boolean sendUserLeaveHint) {
if (!sendUserLeaveHint && task.isLeaf()) {
@@ -1118,6 +1138,9 @@
/** The surface/leash of the task provided by Core. */
SurfaceControl mTaskSurface;
+ /** True when the task is translucent. */
+ final boolean mIsTranslucent;
+
/** The (local) animation-leash created for this task. Only non-null for leafs. */
@Nullable
SurfaceControl mLeash;
@@ -1126,6 +1149,7 @@
mToken = change.getContainer();
mTaskInfo = change.getTaskInfo();
mTaskSurface = change.getLeash();
+ mIsTranslucent = (change.getFlags() & FLAG_TRANSLUCENT) != 0;
mLeash = leash;
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index ac94a6f..9548525 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -3557,6 +3557,36 @@
}
/**
+ * Set a linear block that contain multiple non-encrypted access unit to this
+ * queue request. Exactly one buffer must be set for a queue request before
+ * calling {@link #queue}. Multiple access units if present must be laid out contiguously
+ * and without gaps and in order. An IllegalArgumentException will be thrown
+ * during {@link #queue} if access units are not laid out contiguously.
+ *
+ * @param block The linear block object
+ * @param infos Represents {@link MediaCodec.BufferInfo} objects to mark
+ * individual access-unit boundaries and the timestamps associated with it.
+ * @return this object
+ * @throws IllegalStateException if a buffer is already set
+ */
+ @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+ public @NonNull QueueRequest setMultiFrameLinearBlock(
+ @NonNull LinearBlock block,
+ @NonNull ArrayDeque<BufferInfo> infos) {
+ if (!isAccessible()) {
+ throw new IllegalStateException("The request is stale");
+ }
+ if (mLinearBlock != null || mHardwareBuffer != null) {
+ throw new IllegalStateException("Cannot set block twice");
+ }
+ mLinearBlock = block;
+ mBufferInfos.clear();
+ mBufferInfos.addAll(infos);
+ mCryptoInfos.clear();
+ return this;
+ }
+
+ /**
* Set an encrypted linear block to this queue request. Exactly one buffer must be
* set for a queue request before calling {@link #queue}. It is possible
* to use the same {@link LinearBlock} object for multiple queue
@@ -3691,26 +3721,6 @@
}
/**
- * Sets MediaCodec.BufferInfo objects describing the access units
- * contained in this queue request. Access units must be laid out
- * contiguously without gaps and in order.
- *
- * @param infos Represents {@link MediaCodec.BufferInfo} objects to mark
- * individual access-unit boundaries and the timestamps associated with it.
- * The buffer is expected to contain the data in a continuous manner.
- * @return this object
- */
- @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
- public @NonNull QueueRequest setBufferInfos(@NonNull ArrayDeque<BufferInfo> infos) {
- if (!isAccessible()) {
- throw new IllegalStateException("The request is stale");
- }
- mBufferInfos.clear();
- mBufferInfos.addAll(infos);
- return this;
- }
-
- /**
* Add an integer parameter.
* See {@link MediaFormat} for an exhaustive list of supported keys with
* values of type int, that can also be set with {@link MediaFormat#setInteger}.
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 3174c37..1e7bc47 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -20,10 +20,12 @@
import static android.media.Utils.sortDistinctRanges;
import static android.media.codec.Flags.FLAG_DYNAMIC_COLOR_ASPECTS;
import static android.media.codec.Flags.FLAG_HLG_EDITING;
+import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC;
import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -40,6 +42,8 @@
import android.util.Rational;
import android.util.Size;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -1808,6 +1812,55 @@
}
}
+ /** @hide */
+ @IntDef(prefix = {"SECURITY_MODEL_"}, value = {
+ SECURITY_MODEL_SANDBOXED,
+ SECURITY_MODEL_MEMORY_SAFE,
+ SECURITY_MODEL_TRUSTED_CONTENT_ONLY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SecurityModel {}
+
+ /**
+ * In this model the codec is running in a sandboxed process. Even if a
+ * malicious content was fed to the codecs in this model, the impact will
+ * be contained in the sandboxed process.
+ */
+ @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+ public static final int SECURITY_MODEL_SANDBOXED = 0;
+ /**
+ * In this model the codec is not running in a sandboxed process, but
+ * written in a memory-safe way. It typically means that the software
+ * implementation of the codec is written in a memory-safe language such
+ * as Rust.
+ */
+ @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+ public static final int SECURITY_MODEL_MEMORY_SAFE = 1;
+ /**
+ * In this model the codec is suitable only for trusted content where
+ * the input can be verified to be well-formed and no malicious actor
+ * can alter it. For example, codecs in this model are not suitable
+ * for arbitrary media downloaded from the internet or present in a user
+ * directory. On the other hand, they could be suitable for media encoded
+ * in the backend that the app developer wholly controls.
+ * <p>
+ * Codecs with this security model is not included in
+ * {@link MediaCodecList#REGULAR_CODECS}, but included in
+ * {@link MediaCodecList#ALL_CODECS}.
+ */
+ @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+ public static final int SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 2;
+
+ /**
+ * Query the security model of the codec.
+ */
+ @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+ @SecurityModel
+ public int getSecurityModel() {
+ // TODO b/297922713 --- detect security model of out-of-sandbox codecs
+ return SECURITY_MODEL_SANDBOXED;
+ }
+
/**
* A class that supports querying the video capabilities of a codec.
*/
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 5e40eee..7b83842 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -16,6 +16,8 @@
package android.media;
+import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC;
+
import static com.android.media.codec.flags.Flags.FLAG_CODEC_IMPORTANCE;
import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
@@ -1715,6 +1717,58 @@
@FlaggedApi(FLAG_CODEC_IMPORTANCE)
public static final String KEY_IMPORTANCE = "importance";
+ /** @hide */
+ @IntDef(flag = true, prefix = {"FLAG_SECURITY_MODEL_"}, value = {
+ FLAG_SECURITY_MODEL_SANDBOXED,
+ FLAG_SECURITY_MODEL_MEMORY_SAFE,
+ FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SecurityModelFlag {}
+
+ /**
+ * Flag for {@link MediaCodecInfo#SECURITY_MODEL_SANDBOXED}.
+ */
+ @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+ public static final int FLAG_SECURITY_MODEL_SANDBOXED =
+ (1 << MediaCodecInfo.SECURITY_MODEL_SANDBOXED);
+ /**
+ * Flag for {@link MediaCodecInfo#SECURITY_MODEL_MEMORY_SAFE}.
+ */
+ @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+ public static final int FLAG_SECURITY_MODEL_MEMORY_SAFE =
+ (1 << MediaCodecInfo.SECURITY_MODEL_MEMORY_SAFE);
+ /**
+ * Flag for {@link MediaCodecInfo#SECURITY_MODEL_TRUSTED_CONTENT_ONLY}.
+ */
+ @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+ public static final int FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY =
+ (1 << MediaCodecInfo.SECURITY_MODEL_TRUSTED_CONTENT_ONLY);
+
+ /**
+ * A key describing the requested security model as flags.
+ * <p>
+ * The associated value is a flag of the following values:
+ * {@link FLAG_SECURITY_MODEL_SANDBOXED},
+ * {@link FLAG_SECURITY_MODEL_MEMORY_SAFE},
+ * {@link FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY}. The default value is
+ * {@link FLAG_SECURITY_MODEL_SANDBOXED}.
+ * <p>
+ * When passed to {@link MediaCodecList#findDecoderForFormat} or
+ * {@link MediaCodecList#findEncoderForFormat}, MediaCodecList filters
+ * the security model of the codecs according to this flag value.
+ * <p>
+ * When passed to {@link MediaCodec#configure}, MediaCodec verifies
+ * the security model matches the flag value passed, and throws
+ * {@link java.lang.IllegalArgumentException} if the model does not match.
+ * <p>
+ * @see MediaCodecInfo#getSecurityModel
+ * @see MediaCodecList#findDecoderForFormat
+ * @see MediaCodecList#findEncoderForFormat
+ */
+ @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
+ public static final String KEY_SECURITY_MODEL = "security-model";
+
/* package private */ MediaFormat(@NonNull Map<String, Object> map) {
mMap = map;
}
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index 3254a39..f264b16 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -44,6 +44,8 @@
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -138,6 +140,11 @@
private boolean mCategoryOtherServiceEnabled;
/**
+ * Whether the NFC stack should default to Observe Mode when this preferred service.
+ */
+ private boolean mDefaultToObserveMode;
+
+ /**
* @hide
*/
@UnsupportedAppUsage
@@ -257,6 +264,9 @@
com.android.internal.R.styleable.HostApduService_settingsActivity);
mOffHostName = null;
mStaticOffHostName = mOffHostName;
+ mDefaultToObserveMode = sa.getBoolean(
+ R.styleable.HostApduService_defaultToObserveMode,
+ false);
sa.recycle();
} else {
TypedArray sa = res.obtainAttributes(attrs,
@@ -276,6 +286,9 @@
com.android.internal.R.styleable.HostApduService_settingsActivity);
mOffHostName = sa.getString(
com.android.internal.R.styleable.OffHostApduService_secureElementName);
+ mDefaultToObserveMode = sa.getBoolean(
+ R.styleable.HostApduService_defaultToObserveMode,
+ false);
if (mOffHostName != null) {
if (mOffHostName.equals("eSE")) {
mOffHostName = "eSE1";
@@ -611,6 +624,25 @@
}
/**
+ * Returns whether the NFC stack should default to observe mode when this servise is preferred.
+ * @return whether the NFC stack should default to observe mode when this servise is preferred
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
+ public boolean defaultToObserveMode() {
+ return mDefaultToObserveMode;
+ }
+
+ /**
+ * Sets whether the NFC stack should default to observe mode when this servise is preferred.
+ * @param defaultToObserveMode whether the NFC stack should default to observe mode when this
+ * servise is preferred
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
+ public void setDefaultToObserveMode(boolean defaultToObserveMode) {
+ mDefaultToObserveMode = defaultToObserveMode;
+ }
+
+ /**
* Returns description of service.
* @return user readable description of service
*/
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectView.kt
new file mode 100644
index 0000000..aad593e
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectView.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 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 com.android.systemui.surfaceeffects.loadingeffect
+
+import android.content.Context
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.view.View
+
+/** Custom View for drawing the [LoadingEffect] with [Canvas.drawPaint]. */
+open class LoadingEffectView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
+
+ private var paint: Paint? = null
+ private var blendMode: BlendMode = BlendMode.SRC_OVER
+
+ override fun onDraw(canvas: Canvas) {
+ if (!canvas.isHardwareAccelerated) {
+ return
+ }
+ paint?.let { canvas.drawPaint(it) }
+ }
+
+ /** Designed to be called on [LoadingEffect.PaintDrawCallback.onDraw]. */
+ fun draw(paint: Paint) {
+ this.paint = paint
+ this.paint!!.blendMode = blendMode
+
+ invalidate()
+ }
+
+ /** Sets the blend mode of the [Paint]. */
+ fun setBlendMode(blendMode: BlendMode) {
+ this.blendMode = blendMode
+ }
+}
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index 5db9eee..109e63c 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -67,6 +67,18 @@
android:background="@drawable/qs_media_outline_layout_bg"
/>
+ <com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView
+ android:id="@+id/loading_effect_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_media_session_height_expanded"
+ app:layout_constraintStart_toStartOf="@id/album_art"
+ app:layout_constraintEnd_toEndOf="@id/album_art"
+ app:layout_constraintTop_toTopOf="@id/album_art"
+ app:layout_constraintBottom_toBottomOf="@id/album_art"
+ android:clipToOutline="true"
+ android:background="@drawable/qs_media_outline_layout_bg"
+ />
+
<!-- Guideline for output switcher -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/center_vertical_guideline"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e401c71..57c4230 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1416,6 +1416,9 @@
<!-- Indication on the keyguard that appears when a trust agents unlocks the device. [CHAR LIMIT=40] -->
<string name="keyguard_indication_trust_unlocked">Kept unlocked by TrustAgent</string>
+ <!-- Message asking the user to authenticate with primary authentication methods (PIN/pattern/password) or biometrics after the device is locked by adaptive auth. [CHAR LIMIT=60] -->
+ <string name="kg_prompt_after_adaptive_auth_lock">Theft protection\nDevice locked, too many unlock attempts</string>
+
<!-- Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. [CHAR LIMIT=20] -->
<string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
index c053b33..2f2b10f 100644
--- a/packages/SystemUI/res/xml/media_session_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -55,6 +55,15 @@
app:layout_constraintBottom_toBottomOf="@+id/album_art" />
<Constraint
+ android:id="@+id/loading_effect_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_media_session_height_collapsed"
+ app:layout_constraintStart_toStartOf="@+id/album_art"
+ app:layout_constraintEnd_toEndOf="@+id/album_art"
+ app:layout_constraintTop_toTopOf="@+id/album_art"
+ app:layout_constraintBottom_toBottomOf="@+id/album_art" />
+
+ <Constraint
android:id="@+id/header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 8bf7560d..0140d52 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -48,6 +48,15 @@
app:layout_constraintBottom_toBottomOf="@+id/album_art" />
<Constraint
+ android:id="@+id/loading_effect_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_media_session_height_expanded"
+ app:layout_constraintStart_toStartOf="@+id/album_art"
+ app:layout_constraintEnd_toEndOf="@+id/album_art"
+ app:layout_constraintTop_toTopOf="@+id/album_art"
+ app:layout_constraintBottom_toBottomOf="@+id/album_art" />
+
+ <Constraint
android:id="@+id/header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 3585feb..84c8ea7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -19,6 +19,7 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.WindowInsets.Type.ime;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_ADAPTIVE_AUTH_REQUEST;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT;
@@ -126,6 +127,8 @@
return R.string.kg_prompt_reason_timeout_password;
case PROMPT_REASON_TRUSTAGENT_EXPIRED:
return R.string.kg_prompt_reason_timeout_password;
+ case PROMPT_REASON_ADAPTIVE_AUTH_REQUEST:
+ return R.string.kg_prompt_after_adaptive_auth_lock;
case PROMPT_REASON_NONE:
return 0;
default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index db7ff88..bf8900d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -331,6 +331,9 @@
case PROMPT_REASON_TRUSTAGENT_EXPIRED:
resId = R.string.kg_prompt_reason_timeout_pattern;
break;
+ case PROMPT_REASON_ADAPTIVE_AUTH_REQUEST:
+ resId = R.string.kg_prompt_after_adaptive_auth_lock;
+ break;
case PROMPT_REASON_NONE:
break;
default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index fcff0db..bcab6f0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_ADAPTIVE_AUTH_REQUEST;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT;
@@ -138,6 +139,8 @@
return R.string.kg_prompt_reason_timeout_pin;
case PROMPT_REASON_TRUSTAGENT_EXPIRED:
return R.string.kg_prompt_reason_timeout_pin;
+ case PROMPT_REASON_ADAPTIVE_AUTH_REQUEST:
+ return R.string.kg_prompt_after_adaptive_auth_lock;
case PROMPT_REASON_NONE:
return 0;
default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index 83b1a2c..3e87c1b6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -67,6 +67,11 @@
int PROMPT_REASON_TRUSTAGENT_EXPIRED = 8;
/**
+ * Some auth is required because adaptive auth has determined risk
+ */
+ int PROMPT_REASON_ADAPTIVE_AUTH_REQUEST = 9;
+
+ /**
* Strong auth is required because the device has just booted because of an automatic
* mainline update.
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 536f3af..5d073f1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -35,6 +35,7 @@
import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
import static android.os.BatteryManager.CHARGING_POLICY_DEFAULT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -1570,6 +1571,14 @@
return isEncrypted || isLockDown;
}
+ /**
+ * Whether the device is locked by adaptive auth
+ */
+ public boolean isDeviceLockedByAdaptiveAuth(int userId) {
+ return containsFlag(mStrongAuthTracker.getStrongAuthForUser(userId),
+ SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST);
+ }
+
private boolean containsFlag(int haystack, int needle) {
return (haystack & needle) != 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
index 7b4be02..9c28f1c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
@@ -115,17 +115,11 @@
}
private var overlayView: View? = null
- private var lottie: LottieAnimationView? = null
/** Show the side fingerprint sensor indicator */
private fun show() {
- overlayView?.let {
- if (it.isAttachedToWindow) {
- lottie = it.requireViewById<LottieAnimationView>(R.id.sidefps_animation)
- lottie?.pauseAnimation()
- lottie?.removeAllLottieOnCompositionLoadedListener()
- windowManager.get().removeView(it)
- }
+ if (overlayView?.isAttachedToWindow == true) {
+ return
}
overlayView = layoutInflater.get().inflate(R.layout.sidefps_view, null, false)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
index 8197145..c25e748 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
@@ -50,6 +50,7 @@
import com.android.systemui.res.R.string.kg_primary_auth_locked_out_password
import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pattern
import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pin
+import com.android.systemui.res.R.string.kg_prompt_after_adaptive_auth_lock
import com.android.systemui.res.R.string.kg_prompt_after_dpm_lock
import com.android.systemui.res.R.string.kg_prompt_after_update_password
import com.android.systemui.res.R.string.kg_prompt_after_update_pattern
@@ -208,6 +209,11 @@
} else {
faceLockedOut(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
}
+ } else if (flags.isSomeAuthRequiredAfterAdaptiveAuthRequest) {
+ authRequiredAfterAdaptiveAuthRequest(
+ currentSecurityMode,
+ isFingerprintAuthCurrentlyAllowed.value
+ )
} else if (
trustOrBiometricsAvailable &&
flags.strongerAuthRequiredAfterNonStrongBiometricsTimeout
@@ -464,6 +470,34 @@
}.toMessage()
}
+private fun authRequiredAfterAdaptiveAuthRequest(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) authRequiredAfterAdaptiveAuthRequestFingerprintAllowed(securityMode)
+ else
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_adaptive_auth_lock)
+ SecurityMode.Password ->
+ Pair(keyguard_enter_password, kg_prompt_after_adaptive_auth_lock)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_adaptive_auth_lock)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredAfterAdaptiveAuthRequestFingerprintAllowed(
+ securityMode: SecurityMode
+): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern ->
+ Pair(kg_unlock_with_pattern_or_fp, kg_prompt_after_adaptive_auth_lock)
+ SecurityMode.Password ->
+ Pair(kg_unlock_with_password_or_fp, kg_prompt_after_adaptive_auth_lock)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_prompt_after_adaptive_auth_lock)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
private fun authRequiredAfterUserLockdown(securityMode: SecurityMode): BouncerMessageModel {
return when (securityMode) {
SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_user_lockdown_pattern)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
index e23ec89..00ec1a1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -404,6 +404,7 @@
public static final int INDICATION_TYPE_BIOMETRIC_MESSAGE = 11;
public static final int INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP = 12;
public static final int INDICATION_IS_DISMISSIBLE = 13;
+ public static final int INDICATION_TYPE_ADAPTIVE_AUTH = 14;
@IntDef({
INDICATION_TYPE_NONE,
@@ -419,7 +420,8 @@
INDICATION_TYPE_REVERSE_CHARGING,
INDICATION_TYPE_BIOMETRIC_MESSAGE,
INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
- INDICATION_IS_DISMISSIBLE
+ INDICATION_IS_DISMISSIBLE,
+ INDICATION_TYPE_ADAPTIVE_AUTH
})
@Retention(RetentionPolicy.SOURCE)
public @interface IndicationType{}
@@ -455,6 +457,8 @@
return "biometric_message";
case INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP:
return "biometric_message_followup";
+ case INDICATION_TYPE_ADAPTIVE_AUTH:
+ return "adaptive_auth";
default:
return "unknown[" + type + "]";
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 63fd608..641b967 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -30,6 +30,7 @@
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_OCCLUSION;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_UNLOCK_ANIMATION;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -920,15 +921,17 @@
return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
} else if ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
+ } else if (any && ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0
+ || mUpdateMonitor.isFingerprintLockedOut())) {
+ return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT;
+ } else if ((strongAuth & SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST) != 0) {
+ return KeyguardSecurityView.PROMPT_REASON_ADAPTIVE_AUTH_REQUEST;
} else if (trustAgentsEnabled
&& (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) {
return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
} else if (trustAgentsEnabled
&& (strongAuth & SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED) != 0) {
return KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED;
- } else if (any && ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0
- || mUpdateMonitor.isFingerprintLockedOut())) {
- return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT;
} else if (any && (strongAuth & STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE) != 0) {
return KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
} else if (any && (strongAuth
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/AuthenticationFlags.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/AuthenticationFlags.kt
index cf5b88f..08904b6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/AuthenticationFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/AuthenticationFlags.kt
@@ -60,6 +60,12 @@
LockPatternUtils.StrongAuthTracker
.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT
)
+
+ val isSomeAuthRequiredAfterAdaptiveAuthRequest =
+ containsFlag(
+ flag,
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST
+ )
}
private fun containsFlag(haystack: Int, needle: Int): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
index 1b14f75..898eacf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
@@ -25,8 +25,9 @@
import android.widget.TextView
import androidx.constraintlayout.widget.Barrier
import com.android.internal.widget.CachingIconView
-import com.android.systemui.res.R
import com.android.systemui.media.controls.models.GutsViewHolder
+import com.android.systemui.res.R
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView
import com.android.systemui.surfaceeffects.ripple.MultiRippleView
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseView
import com.android.systemui.util.animation.TransitionLayout
@@ -42,6 +43,7 @@
val multiRippleView = itemView.requireViewById<MultiRippleView>(R.id.touch_ripple_view)
val turbulenceNoiseView =
itemView.requireViewById<TurbulenceNoiseView>(R.id.turbulence_noise_view)
+ val loadingEffectView = itemView.requireViewById<LoadingEffectView>(R.id.loading_effect_view)
val appIcon = itemView.requireViewById<ImageView>(R.id.icon)
val titleText = itemView.requireViewById<TextView>(R.id.header_title)
val artistText = itemView.requireViewById<TextView>(R.id.header_artist)
@@ -171,6 +173,7 @@
setOf(
R.id.album_art,
R.id.turbulence_noise_view,
+ R.id.loading_effect_view,
R.id.touch_ripple_view,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
index c87fd14..952f9b8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
@@ -29,6 +29,7 @@
import com.android.settingslib.Utils
import com.android.systemui.media.controls.models.player.MediaViewHolder
import com.android.systemui.monet.ColorScheme
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect
import com.android.systemui.surfaceeffects.ripple.MultiRippleController
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseController
@@ -118,6 +119,7 @@
turbulenceNoiseController,
::AnimatingColorTransition
)
+ var loadingEffect: LoadingEffect? = null
val bgColor = context.getColor(com.google.android.material.R.color.material_dynamic_neutral20)
val surfaceColor =
@@ -128,7 +130,6 @@
mediaViewHolder.albumView.backgroundTintList = colorList
mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor)
}
-
val accentPrimary =
animatingColorTransitionFactory(
loadDefaultColor(R.attr.textColorPrimary),
@@ -139,6 +140,7 @@
mediaViewHolder.gutsViewHolder.setAccentPrimaryColor(accentPrimary)
multiRippleController.updateColor(accentPrimary)
turbulenceNoiseController.updateNoiseColor(accentPrimary)
+ loadingEffect?.updateColor(accentPrimary)
}
val accentSecondary =
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index aa92814..e97c9d3d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -41,6 +41,7 @@
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
+import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.BitmapDrawable;
@@ -81,6 +82,7 @@
import com.android.internal.widget.CachingIconView;
import com.android.settingslib.widget.AdaptiveIcon;
import com.android.systemui.ActivityIntentHelper;
+import com.android.systemui.Flags;
import com.android.systemui.animation.ActivityTransitionAnimator;
import com.android.systemui.animation.GhostedViewTransitionAnimatorController;
import com.android.systemui.bluetooth.BroadcastDialogController;
@@ -111,6 +113,9 @@
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect;
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState;
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView;
import com.android.systemui.surfaceeffects.ripple.MultiRippleController;
import com.android.systemui.surfaceeffects.ripple.MultiRippleView;
import com.android.systemui.surfaceeffects.ripple.RippleAnimation;
@@ -248,13 +253,34 @@
private String mCurrentBroadcastApp;
private MultiRippleController mMultiRippleController;
private TurbulenceNoiseController mTurbulenceNoiseController;
+ private LoadingEffect mLoadingEffect;
private final GlobalSettings mGlobalSettings;
-
+ private final Random mRandom = new Random();
private TurbulenceNoiseAnimationConfig mTurbulenceNoiseAnimationConfig;
private boolean mWasPlaying = false;
private boolean mButtonClicked = false;
- private final Random mRandom = new Random();
+ private final LoadingEffect.Companion.PaintDrawCallback mNoiseDrawCallback =
+ new LoadingEffect.Companion.PaintDrawCallback() {
+ @Override
+ public void onDraw(@NonNull Paint loadingPaint) {
+ mMediaViewHolder.getLoadingEffectView().draw(loadingPaint);
+ }
+ };
+ private final LoadingEffect.Companion.AnimationStateChangedCallback mStateChangedCallback =
+ new LoadingEffect.Companion.AnimationStateChangedCallback() {
+ @Override
+ public void onStateChanged(@NonNull AnimationState oldState,
+ @NonNull AnimationState newState) {
+ LoadingEffectView loadingEffectView =
+ mMediaViewHolder.getLoadingEffectView();
+ if (newState == AnimationState.NOT_PLAYING) {
+ loadingEffectView.setVisibility(View.INVISIBLE);
+ } else {
+ loadingEffectView.setVisibility(View.VISIBLE);
+ }
+ }
+ };
/**
* Initialize a new control panel
@@ -456,6 +482,10 @@
TurbulenceNoiseView turbulenceNoiseView = vh.getTurbulenceNoiseView();
turbulenceNoiseView.setBlendMode(BlendMode.SCREEN);
+ LoadingEffectView loadingEffectView = vh.getLoadingEffectView();
+ loadingEffectView.setBlendMode(BlendMode.SCREEN);
+ loadingEffectView.setVisibility(View.INVISIBLE);
+
mTurbulenceNoiseController = new TurbulenceNoiseController(turbulenceNoiseView);
mColorSchemeTransition = new ColorSchemeTransition(
@@ -587,22 +617,41 @@
}
}
- // Turbulence noise
if (shouldPlayTurbulenceNoise()) {
+ // Need to create the config here to get the correct view size and color.
if (mTurbulenceNoiseAnimationConfig == null) {
mTurbulenceNoiseAnimationConfig =
- createTurbulenceNoiseAnimation();
+ createTurbulenceNoiseConfig();
}
- // Color will be correctly updated in ColorSchemeTransition.
- mTurbulenceNoiseController.play(
- Type.SIMPLEX_NOISE,
- mTurbulenceNoiseAnimationConfig
- );
- mMainExecutor.executeDelayed(
- mTurbulenceNoiseController::finish,
- TURBULENCE_NOISE_PLAY_DURATION
- );
+
+ if (Flags.shaderlibLoadingEffectRefactor()) {
+ if (mLoadingEffect == null) {
+ mLoadingEffect = new LoadingEffect(
+ Type.SIMPLEX_NOISE,
+ mTurbulenceNoiseAnimationConfig,
+ mNoiseDrawCallback,
+ mStateChangedCallback
+ );
+ mColorSchemeTransition.setLoadingEffect(mLoadingEffect);
+ }
+
+ mLoadingEffect.play();
+ mMainExecutor.executeDelayed(
+ mLoadingEffect::finish,
+ TURBULENCE_NOISE_PLAY_DURATION
+ );
+ } else {
+ mTurbulenceNoiseController.play(
+ Type.SIMPLEX_NOISE,
+ mTurbulenceNoiseAnimationConfig
+ );
+ mMainExecutor.executeDelayed(
+ mTurbulenceNoiseController::finish,
+ TURBULENCE_NOISE_PLAY_DURATION
+ );
+ }
}
+
mButtonClicked = false;
mWasPlaying = isPlaying();
@@ -1232,7 +1281,13 @@
return mButtonClicked && !mWasPlaying && isPlaying();
}
- private TurbulenceNoiseAnimationConfig createTurbulenceNoiseAnimation() {
+ private TurbulenceNoiseAnimationConfig createTurbulenceNoiseConfig() {
+ View targetView = Flags.shaderlibLoadingEffectRefactor()
+ ? mMediaViewHolder.getLoadingEffectView() :
+ mMediaViewHolder.getTurbulenceNoiseView();
+ int width = targetView.getWidth();
+ int height = targetView.getHeight();
+
return new TurbulenceNoiseAnimationConfig(
/* gridCount= */ 2.14f,
TurbulenceNoiseAnimationConfig.DEFAULT_LUMINOSITY_MULTIPLIER,
@@ -1242,10 +1297,11 @@
/* noiseMoveSpeedX= */ 0.42f,
/* noiseMoveSpeedY= */ 0f,
TurbulenceNoiseAnimationConfig.DEFAULT_NOISE_SPEED_Z,
+ // Color will be correctly updated in ColorSchemeTransition.
/* color= */ mColorSchemeTransition.getAccentPrimary().getCurrentColor(),
/* backgroundColor= */ Color.BLACK,
- /* width= */ mMediaViewHolder.getTurbulenceNoiseView().getWidth(),
- /* height= */ mMediaViewHolder.getTurbulenceNoiseView().getHeight(),
+ width,
+ height,
TurbulenceNoiseAnimationConfig.DEFAULT_MAX_DURATION_IN_MILLIS,
/* easeInDuration= */ 1350f,
/* easeOutDuration= */ 1350f,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
index 092f1ed..152f193 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
@@ -44,6 +44,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.RegisterStatusBarResult;
import com.android.settingslib.applications.InterestingConfigChanges;
@@ -89,7 +90,16 @@
private final TaskbarDelegate mTaskbarDelegate;
private final NavBarHelper mNavBarHelper;
private int mNavMode;
+ /**
+ * Indicates whether the active display is a large screen, e.g. tablets, foldable devices in
+ * the unfolded state.
+ */
@VisibleForTesting boolean mIsLargeScreen;
+ /**
+ * Indicates whether the device is a phone, rather than everything else (e.g. foldables,
+ * tablets) is considered not a handheld device.
+ */
+ @VisibleForTesting boolean mIsPhone;
/** A displayId - nav bar maps. */
@VisibleForTesting
@@ -139,6 +149,8 @@
dumpManager, autoHideController, lightBarController, pipOptional,
backAnimation.orElse(null), taskStackChangeListeners);
mIsLargeScreen = isLargeScreen(mContext);
+ mIsPhone =
+ mContext.getResources().getIntArray(R.array.config_foldedDeviceStates).length == 0;
dumpManager.registerDumpable(this);
}
@@ -253,9 +265,8 @@
/** @return {@code true} if taskbar is enabled, false otherwise */
private boolean initializeTaskbarIfNecessary() {
- // Enable for large screens or (phone AND flag is set); assuming phone = !mIsLargeScreen
- boolean taskbarEnabled = (mIsLargeScreen || enableTaskbarNavbarUnification())
- && shouldCreateNavBarAndTaskBar(mContext.getDisplayId());
+ boolean taskbarEnabled = supportsTaskbar() && shouldCreateNavBarAndTaskBar(
+ mContext.getDisplayId());
if (taskbarEnabled) {
Trace.beginSection("NavigationBarController#initializeTaskbarIfNecessary");
@@ -274,6 +285,12 @@
return taskbarEnabled;
}
+ @VisibleForTesting
+ boolean supportsTaskbar() {
+ // Enable for tablets, unfolded state on a foldable device or (non handheld AND flag is set)
+ return mIsLargeScreen || (!mIsPhone && enableTaskbarNavbarUnification());
+ }
+
private final CommandQueue.Callbacks mCommandQueueCallbacks = new CommandQueue.Callbacks() {
@Override
public void onDisplayRemoved(int displayId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 14230ba..19fe60a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar;
+import static android.adaptiveauth.Flags.enableAdaptiveAuth;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_MANAGEMENT_DISCLOSURE;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE;
@@ -32,6 +33,7 @@
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.IMPORTANT_MSG_MIN_DURATION;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_IS_DISMISSIBLE;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ADAPTIVE_AUTH;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE;
@@ -454,6 +456,9 @@
updateLockScreenAlignmentMsg();
updateLockScreenLogoutView();
updateLockScreenPersistentUnlockMsg();
+ if (enableAdaptiveAuth()) {
+ updateLockScreenAdaptiveAuthMsg(userId);
+ }
}
private void updateOrganizedOwnedDevice() {
@@ -740,6 +745,22 @@
}
}
+ private void updateLockScreenAdaptiveAuthMsg(int userId) {
+ final boolean deviceLocked = mKeyguardUpdateMonitor.isDeviceLockedByAdaptiveAuth(userId);
+ if (deviceLocked) {
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_ADAPTIVE_AUTH,
+ new KeyguardIndication.Builder()
+ .setMessage(mContext
+ .getString(R.string.kg_prompt_after_adaptive_auth_lock))
+ .setTextColor(mInitialTextColorState)
+ .build(),
+ true);
+ } else {
+ mRotateTextViewController.hideIndication(INDICATION_TYPE_ADAPTIVE_AUTH);
+ }
+ }
+
private boolean isOrganizationOwnedDevice() {
return mDevicePolicyManager.isDeviceManaged()
|| mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 2a4753d..9916ef6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -749,7 +749,7 @@
|| isNotifUserRedacted;
boolean notificationRequestsRedaction =
- ent.getSbn().getNotification().visibility == Notification.VISIBILITY_PRIVATE;
+ ent.isNotificationVisibilityPrivate();
boolean userForcesRedaction = packageHasVisibilityOverride(ent.getSbn().getKey());
if (keyguardPrivateNotifications()) {
@@ -767,9 +767,7 @@
}
NotificationEntry entry = mCommonNotifCollectionLazy.get().getEntry(key);
if (mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD)) {
- return entry != null && entry.getRanking().getChannel() != null
- && entry.getRanking().getChannel().getLockscreenVisibility()
- == Notification.VISIBILITY_PRIVATE;
+ return entry != null && entry.isChannelVisibilityPrivate();
} else {
return entry != null
&& entry.getRanking().getLockscreenVisibilityOverride()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 8678f0a..e111525 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -998,6 +998,23 @@
return style == null ? "nostyle" : style.getSimpleName();
}
+ /**
+ * Return {@code true} if notification's visibility is {@link Notification.VISIBILITY_PRIVATE}
+ */
+ public boolean isNotificationVisibilityPrivate() {
+ return getSbn().getNotification().visibility == Notification.VISIBILITY_PRIVATE;
+ }
+
+ /**
+ * Return {@code true} if notification's channel lockscreen visibility is
+ * {@link Notification.VISIBILITY_PRIVATE}
+ */
+ public boolean isChannelVisibilityPrivate() {
+ return getRanking().getChannel() != null
+ && getRanking().getChannel().getLockscreenVisibility()
+ == Notification.VISIBILITY_PRIVATE;
+ }
+
/** Information about a suggestion that is being edited. */
public static class EditedSuggestionInfo {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
index 2b0a92c..6956a7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
@@ -221,10 +221,15 @@
// Exempt foreground service notifications from protection in effort to keep screen share
// stop actions easily accessible
StatusBarNotification sbn = entry.getSbn();
- if (sbn.getNotification().isFgsOrUij()) {
- return !sbn.getPackageName().equals(projection.getPackageName());
+ if (sbn.getNotification().isFgsOrUij()
+ && sbn.getPackageName().equals(projection.getPackageName())) {
+ return false;
}
- return true;
+ // Only protect/redact notifications if the developer has not explicitly set notification
+ // visibility as public and users has not adjusted default channel visibility to private
+ boolean notificationRequestsRedaction = entry.isNotificationVisibilityPrivate();
+ boolean userForcesRedaction = entry.isChannelVisibilityPrivate();
+ return notificationRequestsRedaction || userForcesRedaction;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 2732047..0957748 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -21,6 +21,7 @@
import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_TIMEOUT;
import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
@@ -650,6 +651,25 @@
}
@Test
+ public void testBouncerPrompt_deviceLockedByAdaptiveAuth() {
+ // GIVEN no trust agents enabled and biometrics aren't enrolled
+ when(mUpdateMonitor.isTrustUsuallyManaged(anyInt())).thenReturn(false);
+ when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(false);
+
+ // WHEN the strong auth reason is SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST
+ KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+ mock(KeyguardUpdateMonitor.StrongAuthTracker.class);
+ when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(strongAuthTracker);
+ when(strongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+ when(strongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
+ SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST);
+
+ // THEN the bouncer prompt reason should return PROMPT_REASON_ADAPTIVE_AUTH_REQUEST
+ assertEquals(KeyguardSecurityView.PROMPT_REASON_ADAPTIVE_AUTH_REQUEST,
+ mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
+ }
+
+ @Test
public void testBouncerPrompt_deviceRestartedDueToMainlineUpdate() {
// GIVEN biometrics enrolled
when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index 5996502..c896486 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -40,6 +40,7 @@
import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.os.Bundle
+import android.platform.test.annotations.EnableFlags
import android.provider.Settings
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.testing.AndroidTestingRunner
@@ -61,6 +62,7 @@
import com.android.internal.logging.InstanceId
import com.android.internal.widget.CachingIconView
import com.android.systemui.ActivityIntentHelper
+import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.bluetooth.BroadcastDialogController
import com.android.systemui.broadcast.BroadcastSender
@@ -88,6 +90,7 @@
import com.android.systemui.res.R
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView
import com.android.systemui.surfaceeffects.ripple.MultiRippleView
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseAnimationConfig
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseView
@@ -190,6 +193,7 @@
private lateinit var dismissText: TextView
private lateinit var multiRippleView: MultiRippleView
private lateinit var turbulenceNoiseView: TurbulenceNoiseView
+ private lateinit var loadingEffectView: LoadingEffectView
private lateinit var session: MediaSession
private lateinit var device: MediaDeviceData
@@ -402,6 +406,7 @@
multiRippleView = MultiRippleView(context, null)
turbulenceNoiseView = TurbulenceNoiseView(context, null)
+ loadingEffectView = LoadingEffectView(context, null)
whenever(viewHolder.player).thenReturn(view)
whenever(viewHolder.appIcon).thenReturn(appIcon)
@@ -447,6 +452,7 @@
whenever(viewHolder.multiRippleView).thenReturn(multiRippleView)
whenever(viewHolder.turbulenceNoiseView).thenReturn(turbulenceNoiseView)
+ whenever(viewHolder.loadingEffectView).thenReturn(loadingEffectView)
}
/** Initialize elements for the recommendation view holder */
@@ -2429,6 +2435,7 @@
mainExecutor.execute {
assertThat(turbulenceNoiseView.visibility).isEqualTo(View.VISIBLE)
+ assertThat(loadingEffectView.visibility).isEqualTo(View.INVISIBLE)
clock.advanceTime(
MediaControlPanel.TURBULENCE_NOISE_PLAY_DURATION +
@@ -2436,6 +2443,40 @@
)
assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
+ assertThat(loadingEffectView.visibility).isEqualTo(View.INVISIBLE)
+ }
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_SHADERLIB_LOADING_EFFECT_REFACTOR)
+ fun playTurbulenceNoise_newLoadingEffect_finishesAfterDuration() {
+ val semanticActions =
+ MediaButton(
+ playOrPause =
+ MediaAction(
+ icon = null,
+ action = {},
+ contentDescription = "play",
+ background = null
+ )
+ )
+ val data = mediaData.copy(semanticActions = semanticActions)
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.actionPlayPause.callOnClick()
+
+ mainExecutor.execute {
+ assertThat(loadingEffectView.visibility).isEqualTo(View.VISIBLE)
+ assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
+
+ clock.advanceTime(
+ MediaControlPanel.TURBULENCE_NOISE_PLAY_DURATION +
+ TurbulenceNoiseAnimationConfig.DEFAULT_EASING_DURATION_IN_MILLIS.toLong()
+ )
+
+ assertThat(loadingEffectView.visibility).isEqualTo(View.INVISIBLE)
+ assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
}
}
@@ -2458,6 +2499,30 @@
viewHolder.action0.callOnClick()
assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
+ assertThat(loadingEffectView.visibility).isEqualTo(View.INVISIBLE)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_SHADERLIB_LOADING_EFFECT_REFACTOR)
+ fun playTurbulenceNoise_newLoadingEffect_whenPlaybackStateIsNotPlaying_doesNotPlayTurbulence() {
+ val semanticActions =
+ MediaButton(
+ custom0 =
+ MediaAction(
+ icon = null,
+ action = {},
+ contentDescription = "custom0",
+ background = null
+ ),
+ )
+ val data = mediaData.copy(semanticActions = semanticActions)
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.action0.callOnClick()
+
+ assertThat(loadingEffectView.visibility).isEqualTo(View.INVISIBLE)
+ assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
index bfb18c8..52859cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerImplTest.java
@@ -22,6 +22,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -289,32 +291,43 @@
verify(mCommandQueue, never()).addCallback(any(TaskbarDelegate.class));
}
-
@Test
public void testConfigurationChange_taskbarNotInitialized() {
Configuration configuration = mContext.getResources().getConfiguration();
- when(Utilities.isLargeScreen(any())).thenReturn(true);
+ mNavigationBarController.mIsLargeScreen = true;
mNavigationBarController.onConfigChanged(configuration);
verify(mTaskbarDelegate, never()).onConfigurationChanged(configuration);
}
@Test
- public void testConfigurationChangeUnfolding_taskbarInitialized() {
+ public void testConfigurationChange_taskbarInitialized() {
Configuration configuration = mContext.getResources().getConfiguration();
- when(Utilities.isLargeScreen(any())).thenReturn(true);
+ mNavigationBarController.mIsLargeScreen = true;
when(mTaskbarDelegate.isInitialized()).thenReturn(true);
mNavigationBarController.onConfigChanged(configuration);
verify(mTaskbarDelegate, times(1)).onConfigurationChanged(configuration);
}
@Test
- public void testConfigurationChangeFolding_taskbarInitialized() {
+ public void testShouldRenderTaskbar_taskbarNotRenderedOnPhone() {
+ mNavigationBarController.mIsLargeScreen = false;
+ mNavigationBarController.mIsPhone = true;
+ assertFalse(mNavigationBarController.supportsTaskbar());
+ }
+
+ @Test
+ public void testShouldRenderTaskbar_taskbarRenderedOnTabletOrUnfolded() {
+ mNavigationBarController.mIsLargeScreen = true;
+ mNavigationBarController.mIsPhone = false;
+ assertTrue(mNavigationBarController.supportsTaskbar());
+ }
+
+ @Test
+ public void testShouldRenderTaskbar_taskbarRenderedInFoldedState() {
assumeTrue(enableTaskbarNavbarUnification());
- Configuration configuration = mContext.getResources().getConfiguration();
- when(Utilities.isLargeScreen(any())).thenReturn(false);
- when(mTaskbarDelegate.isInitialized()).thenReturn(true);
- mNavigationBarController.onConfigChanged(configuration);
- verify(mTaskbarDelegate, times(1)).onConfigurationChanged(configuration);
+ mNavigationBarController.mIsLargeScreen = false;
+ mNavigationBarController.mIsPhone = false;
+ assertTrue(mNavigationBarController.supportsTaskbar());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index ccc9dc0..8a48fe1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -50,8 +50,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.util.time.FakeSystemClock;
@@ -280,6 +280,66 @@
}
@Test
+ public void testIsNotificationVisibilityPrivate_true() {
+ assertTrue(mEntry.isNotificationVisibilityPrivate());
+ }
+
+ @Test
+ public void testIsNotificationVisibilityPrivate_visibilityPublic_false() {
+ Notification.Builder notification = new Notification.Builder(mContext, "")
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setSmallIcon(R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text");
+
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setChannel(mChannel)
+ .setId(mId++)
+ .setNotification(notification.build())
+ .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .build();
+
+ assertFalse(entry.isNotificationVisibilityPrivate());
+ }
+
+ @Test
+ public void testIsChannelVisibilityPrivate_true() {
+ assertTrue(mEntry.isChannelVisibilityPrivate());
+ }
+
+ @Test
+ public void testIsChannelVisibilityPrivate_visibilityPublic_false() {
+ NotificationChannel channel =
+ new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
+ channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
+ StatusBarNotification sbn = new SbnBuilder().build();
+ Ranking ranking = new RankingBuilder()
+ .setChannel(channel)
+ .setKey(sbn.getKey())
+ .build();
+ NotificationEntry entry =
+ new NotificationEntry(sbn, ranking, mClock.uptimeMillis());
+
+ assertFalse(entry.isChannelVisibilityPrivate());
+ }
+
+ @Test
+ public void testIsChannelVisibilityPrivate_entryHasNoChannel_false() {
+ StatusBarNotification sbn = new SbnBuilder().build();
+ Ranking ranking = new RankingBuilder()
+ .setChannel(null)
+ .setKey(sbn.getKey())
+ .build();
+ NotificationEntry entry =
+ new NotificationEntry(sbn, ranking, mClock.uptimeMillis());
+
+ assertFalse(entry.isChannelVisibilityPrivate());
+ }
+
+ @Test
public void notificationDataEntry_testIsLastMessageFromReply() {
Person.Builder person = new Person.Builder()
.setName("name")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
index 1dac642..a2af38f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
@@ -19,17 +19,24 @@
import android.app.ActivityOptions
import android.app.IActivityManager
import android.app.Notification
+import android.app.Notification.FLAG_FOREGROUND_SERVICE
+import android.app.Notification.VISIBILITY_PRIVATE
+import android.app.Notification.VISIBILITY_PUBLIC
+import android.app.NotificationChannel
+import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE
import android.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
import android.platform.test.annotations.EnableFlags
import android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS
-import android.service.notification.StatusBarNotification
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.server.notification.Flags
import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.RankingBuilder
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.concurrency.mockExecutorHandler
import com.android.systemui.util.mockito.whenever
@@ -316,6 +323,25 @@
assertFalse(controller.shouldProtectNotification(notificationEntry))
}
+ @Test
+ fun shouldProtectNotification_projectionActive_publicNotification_false() {
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ // App marked notification visibility as public
+ val notificationEntry = setupPublicNotificationEntry(TEST_PROJECTION_PACKAGE_NAME)
+
+ assertFalse(controller.shouldProtectNotification(notificationEntry))
+ }
+
+ @Test
+ fun shouldProtectNotification_projectionActive_publicNotificationUserChannelOverride_true() {
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ val notificationEntry =
+ setupPublicNotificationEntryWithUserOverriddenChannel(TEST_PROJECTION_PACKAGE_NAME)
+
+ assertTrue(controller.shouldProtectNotification(notificationEntry))
+ }
private fun setDisabledViaDeveloperOption() {
globalSettings.putInt(DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 1)
@@ -336,21 +362,50 @@
private fun setupNotificationEntry(
packageName: String,
- isFgs: Boolean = false
+ isFgs: Boolean = false,
+ overrideVisibility: Boolean = false,
+ overrideChannelVisibility: Boolean = false,
): NotificationEntry {
- val notificationEntry = mock(NotificationEntry::class.java)
- val sbn = mock(StatusBarNotification::class.java)
- val notification = mock(Notification::class.java)
- whenever(notificationEntry.sbn).thenReturn(sbn)
- whenever(sbn.packageName).thenReturn(packageName)
- whenever(sbn.notification).thenReturn(notification)
- whenever(notification.isFgsOrUij).thenReturn(isFgs)
-
+ val notification = Notification()
+ if (isFgs) {
+ notification.flags = notification.flags or FLAG_FOREGROUND_SERVICE
+ }
+ if (overrideVisibility) {
+ // Developer has marked notification as public
+ notification.visibility = VISIBILITY_PUBLIC
+ }
+ val notificationEntry =
+ NotificationEntryBuilder().setNotification(notification).setPkg(packageName).build()
+ val channel = NotificationChannel("1", "1", IMPORTANCE_HIGH)
+ if (overrideChannelVisibility) {
+ // User doesn't allow private notifications at the channel level
+ channel.lockscreenVisibility = VISIBILITY_PRIVATE
+ }
+ notificationEntry.setRanking(
+ RankingBuilder(notificationEntry.ranking)
+ .setChannel(channel)
+ .setVisibilityOverride(VISIBILITY_NO_OVERRIDE)
+ .build()
+ )
return notificationEntry
}
private fun setupFgsNotificationEntry(packageName: String): NotificationEntry {
- return setupNotificationEntry(packageName, /* isFgs= */ true)
+ return setupNotificationEntry(packageName, isFgs = true)
+ }
+
+ private fun setupPublicNotificationEntry(packageName: String): NotificationEntry {
+ return setupNotificationEntry(packageName, overrideVisibility = true)
+ }
+
+ private fun setupPublicNotificationEntryWithUserOverriddenChannel(
+ packageName: String
+ ): NotificationEntry {
+ return setupNotificationEntry(
+ packageName,
+ overrideVisibility = true,
+ overrideChannelVisibility = true
+ )
}
companion object {
diff --git a/ravenwood/run-ravenwood-tests.sh b/ravenwood/run-ravenwood-tests.sh
index 3f4b8a7..259aa70 100755
--- a/ravenwood/run-ravenwood-tests.sh
+++ b/ravenwood/run-ravenwood-tests.sh
@@ -13,10 +13,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Run all the ravenwood tests.
+# Run all the ravenwood tests + hoststubgen unit tests.
+
+all_tests="hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test"
# "echo" is to remove the newlines
-all_tests=$(echo $(${0%/*}/list-ravenwood-tests.sh) )
+all_tests="$all_tests $(echo $(${0%/*}/list-ravenwood-tests.sh) )"
echo "Running tests: $all_tests"
atest $all_tests
diff --git a/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
new file mode 100644
index 0000000..3312be2
--- /dev/null
+++ b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2024 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 com.android.server.adaptiveauth;
+
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.hardware.biometrics.AuthenticationStateListener;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.BiometricSourceType;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseIntArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
+import com.android.internal.widget.LockSettingsStateListener;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.pm.UserManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
+
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+public class AdaptiveAuthService extends SystemService {
+ private static final String TAG = "AdaptiveAuthService";
+ private static final boolean DEBUG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.DEBUG);
+
+ @VisibleForTesting
+ static final int MAX_ALLOWED_FAILED_AUTH_ATTEMPTS = 5;
+ private static final int MSG_REPORT_PRIMARY_AUTH_ATTEMPT = 1;
+ private static final int MSG_REPORT_BIOMETRIC_AUTH_ATTEMPT = 2;
+ private static final int AUTH_SUCCESS = 1;
+ private static final int AUTH_FAILURE = 0;
+
+ private final LockPatternUtils mLockPatternUtils;
+ private final LockSettingsInternal mLockSettings;
+ private final BiometricManager mBiometricManager;
+ private final KeyguardManager mKeyguardManager;
+ private final PowerManager mPowerManager;
+ private final WindowManagerInternal mWindowManager;
+ private final UserManagerInternal mUserManager;
+ @VisibleForTesting
+ final SparseIntArray mFailedAttemptsForUser = new SparseIntArray();
+
+ public AdaptiveAuthService(Context context) {
+ this(context, new LockPatternUtils(context));
+ }
+
+ @VisibleForTesting
+ public AdaptiveAuthService(Context context, LockPatternUtils lockPatternUtils) {
+ super(context);
+ mLockPatternUtils = lockPatternUtils;
+ mLockSettings = Objects.requireNonNull(
+ LocalServices.getService(LockSettingsInternal.class));
+ mBiometricManager = Objects.requireNonNull(
+ context.getSystemService(BiometricManager.class));
+ mKeyguardManager = Objects.requireNonNull(context.getSystemService(KeyguardManager.class));
+ mPowerManager = Objects.requireNonNull(context.getSystemService(PowerManager.class));
+ mWindowManager = Objects.requireNonNull(
+ LocalServices.getService(WindowManagerInternal.class));
+ mUserManager = Objects.requireNonNull(LocalServices.getService(UserManagerInternal.class));
+ }
+
+ @Override
+ public void onStart() {}
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ init();
+ }
+ }
+
+ @VisibleForTesting
+ void init() {
+ mLockSettings.registerLockSettingsStateListener(mLockSettingsStateListener);
+ mBiometricManager.registerAuthenticationStateListener(mAuthenticationStateListener);
+ }
+
+ private final LockSettingsStateListener mLockSettingsStateListener =
+ new LockSettingsStateListener() {
+ @Override
+ public void onAuthenticationSucceeded(int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "LockSettingsStateListener#onAuthenticationSucceeded");
+ }
+ mHandler.obtainMessage(MSG_REPORT_PRIMARY_AUTH_ATTEMPT, AUTH_SUCCESS, userId)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onAuthenticationFailed(int userId) {
+ Slog.i(TAG, "LockSettingsStateListener#onAuthenticationFailed");
+ mHandler.obtainMessage(MSG_REPORT_PRIMARY_AUTH_ATTEMPT, AUTH_FAILURE, userId)
+ .sendToTarget();
+ }
+ };
+
+ private final AuthenticationStateListener mAuthenticationStateListener =
+ new AuthenticationStateListener.Stub() {
+ @Override
+ public void onAuthenticationStarted(int requestReason) {}
+
+ @Override
+ public void onAuthenticationStopped() {}
+
+ @Override
+ public void onAuthenticationSucceeded(int requestReason, int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "AuthenticationStateListener#onAuthenticationSucceeded");
+ }
+ mHandler.obtainMessage(MSG_REPORT_BIOMETRIC_AUTH_ATTEMPT, AUTH_SUCCESS, userId)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onAuthenticationFailed(int requestReason, int userId) {
+ Slog.i(TAG, "AuthenticationStateListener#onAuthenticationFailed");
+ mHandler.obtainMessage(MSG_REPORT_BIOMETRIC_AUTH_ATTEMPT, AUTH_FAILURE, userId)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onAuthenticationAcquired(BiometricSourceType biometricSourceType,
+ int requestReason, int acquiredInfo) {}
+ };
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_REPORT_PRIMARY_AUTH_ATTEMPT:
+ handleReportPrimaryAuthAttempt(msg.arg1 != AUTH_FAILURE, msg.arg2);
+ break;
+ case MSG_REPORT_BIOMETRIC_AUTH_ATTEMPT:
+ handleReportBiometricAuthAttempt(msg.arg1 != AUTH_FAILURE, msg.arg2);
+ break;
+ }
+ }
+ };
+
+ private void handleReportPrimaryAuthAttempt(boolean success, int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "handleReportPrimaryAuthAttempt: success=" + success
+ + ", userId=" + userId);
+ }
+ reportAuthAttempt(success, userId);
+ }
+
+ private void handleReportBiometricAuthAttempt(boolean success, int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "handleReportBiometricAuthAttempt: success=" + success
+ + ", userId=" + userId);
+ }
+ reportAuthAttempt(success, userId);
+ }
+
+ private void reportAuthAttempt(boolean success, int userId) {
+ if (success) {
+ // Deleting the entry effectively resets the counter of failed attempts for the user
+ mFailedAttemptsForUser.delete(userId);
+ return;
+ }
+
+ final int numFailedAttempts = mFailedAttemptsForUser.get(userId, 0) + 1;
+ Slog.i(TAG, "reportAuthAttempt: numFailedAttempts=" + numFailedAttempts
+ + ", userId=" + userId);
+ mFailedAttemptsForUser.put(userId, numFailedAttempts);
+
+ // Don't lock again if the device is already locked and if Keyguard is already showing and
+ // isn't trivially dismissible
+ if (mKeyguardManager.isDeviceLocked(userId) && mKeyguardManager.isKeyguardLocked()) {
+ Slog.d(TAG, "Not locking the device because the device is already locked.");
+ return;
+ }
+
+ if (numFailedAttempts < MAX_ALLOWED_FAILED_AUTH_ATTEMPTS) {
+ Slog.d(TAG, "Not locking the device because the number of failed attempts is below"
+ + " the threshold.");
+ return;
+ }
+
+ //TODO: additionally consider the trust signal before locking device
+ lockDevice(userId);
+ }
+
+ /**
+ * Locks the device and requires primary auth or biometric auth for unlocking
+ */
+ private void lockDevice(int userId) {
+ // Require either primary auth or biometric auth to unlock the device again. Keyguard and
+ // bouncer will also check the StrongAuthFlag for the user to display correct strings for
+ // explaining why the device is locked
+ mLockPatternUtils.requireStrongAuth(SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST, userId);
+
+ // If userId is a profile that has a different parent userId (regardless of its profile
+ // type, or whether it's a profile with unified challenges or not), its parent userId that
+ // owns the Keyguard will also be locked
+ final int parentUserId = mUserManager.getProfileParentId(userId);
+ Slog.i(TAG, "lockDevice: userId=" + userId + ", parentUserId=" + parentUserId);
+ if (parentUserId != userId) {
+ mLockPatternUtils.requireStrongAuth(SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST,
+ parentUserId);
+ }
+
+ // Power off the display
+ mPowerManager.goToSleep(SystemClock.uptimeMillis());
+
+ // Lock the device
+ mWindowManager.lockNow();
+ }
+}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 7d82f0c..df46e5d 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL_IMPLICIT;
import static android.app.ActivityManager.PROCESS_CAPABILITY_BFSL;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
@@ -67,7 +68,10 @@
import static android.content.Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL;
+import static android.media.audio.Flags.foregroundAudioControl;
import static android.os.Process.SCHED_OTHER;
import static android.os.Process.THREAD_GROUP_BACKGROUND;
import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -2266,6 +2270,15 @@
(fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
+ if (foregroundAudioControl()) { // flag check
+ final int fgsAudioType = FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
+ | FOREGROUND_SERVICE_TYPE_CAMERA
+ | FOREGROUND_SERVICE_TYPE_MICROPHONE
+ | FOREGROUND_SERVICE_TYPE_PHONE_CALL;
+ capabilityFromFGS |= (psr.getForegroundServiceTypes() & fgsAudioType) != 0
+ ? PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL : 0;
+ }
+
final boolean enabled = state.getCachedCompatChange(
CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY);
if (enabled) {
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
index f85b03e..1bf779a 100644
--- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -722,14 +722,8 @@
performNewUpdateOomAdjLSP(oomAdjReason, topApp, targetProcesses, activeUids,
fullUpdate, now, UNKNOWN_ADJ);
- if (fullUpdate) {
- assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP());
- } else {
- activeProcesses.clear();
- activeProcesses.addAll(targetProcesses);
- assignCachedAdjIfNecessary(activeProcesses);
- activeProcesses.clear();
- }
+ // TODO: b/319163103 - optimize cache adj assignment to not require the whole lru list.
+ assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP());
postUpdateOomAdjInnerLSP(oomAdjReason, activeUids, now, nowElapsed, oldTime);
targetProcesses.clear();
@@ -996,11 +990,11 @@
&& service.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
|| (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ
&& service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
- && service.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
+ && service.mState.getCurProcState() <= PROCESS_STATE_TOP)
+ || (service.isSdkSandbox && cr.binding.attributedClient != null)) {
continue;
}
-
computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false,
oomAdjReason, cachedAdj, false, false);
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index d23d9fb..9883f09 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1678,7 +1678,11 @@
final ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(j);
for (int k = clist.size() - 1; k >= 0; k--) {
final ConnectionRecord cr = clist.get(k);
- consumer.accept(cr.binding.client);
+ if (isSdkSandbox && cr.binding.attributedClient != null) {
+ consumer.accept(cr.binding.attributedClient);
+ } else {
+ consumer.accept(cr.binding.client);
+ }
}
}
}
@@ -1689,25 +1693,5 @@
consumer.accept(conn.client);
}
}
- // If this process is a sandbox itself, also add the app on whose behalf
- // its running
- if (isSdkSandbox) {
- for (int is = mServices.numberOfRunningServices() - 1; is >= 0; is--) {
- ServiceRecord s = mServices.getRunningServiceAt(is);
- ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections =
- s.getConnections();
- for (int conni = serviceConnections.size() - 1; conni >= 0; conni--) {
- ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni);
- for (int i = clist.size() - 1; i >= 0; i--) {
- ConnectionRecord cr = clist.get(i);
- ProcessRecord attributedApp = cr.binding.attributedClient;
- if (attributedApp == null || attributedApp == this) {
- continue;
- }
- consumer.accept(attributedApp);
- }
- }
- }
- }
}
}
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 57d233e..562beaf 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -205,10 +205,10 @@
}
/**
- * Returns the FGS typps, but it doesn't tell if the types include "NONE" or not, so
- * do not use it outside of this class.
+ * Returns the FGS types, but it doesn't tell if the types include "NONE" or not, use
+ * {@link #hasForegroundServices()}
*/
- private int getForegroundServiceTypes() {
+ int getForegroundServiceTypes() {
return mHasForegroundServices ? mFgServiceTypes : 0;
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 145b213..fd09ad1 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -166,7 +166,6 @@
import com.android.server.LocalManagerRegistry;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
-import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemServiceManager;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.android.server.pm.PackageList;
@@ -1038,7 +1037,7 @@
new Ops(pkgName, uidState));
}
- createSandboxUidStateIfNotExistsForAppLocked(uid);
+ createSandboxUidStateIfNotExistsForAppLocked(uid, null);
}
} else if (action.equals(ACTION_PACKAGE_REMOVED) && !intent.hasExtra(EXTRA_REPLACING)) {
synchronized (AppOpsService.this) {
@@ -1050,69 +1049,8 @@
return;
}
- ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
- ArraySet<String> attributionTags = new ArraySet<>();
- attributionTags.add(null);
- if (pkg.getAttributions() != null) {
- int numAttributions = pkg.getAttributions().size();
- for (int attributionNum = 0; attributionNum < numAttributions;
- attributionNum++) {
- ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
- attributionTags.add(attribution.getTag());
-
- int numInheritFrom = attribution.getInheritFrom().size();
- for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
- inheritFromNum++) {
- dstAttributionTags.put(attribution.getInheritFrom().get(inheritFromNum),
- attribution.getTag());
- }
- }
- }
-
synchronized (AppOpsService.this) {
- UidState uidState = mUidStates.get(uid);
- if (uidState == null) {
- return;
- }
-
- Ops ops = uidState.pkgOps.get(pkgName);
- if (ops == null) {
- return;
- }
-
- // Reset cached package properties to re-initialize when needed
- ops.bypass = null;
- ops.knownAttributionTags.clear();
-
- // Merge data collected for removed attributions into their successor
- // attributions
- int numOps = ops.size();
- for (int opNum = 0; opNum < numOps; opNum++) {
- Op op = ops.valueAt(opNum);
- for (int deviceIndex = op.mDeviceAttributedOps.size() - 1; deviceIndex >= 0;
- deviceIndex--) {
- ArrayMap<String, AttributedOp> attributedOps =
- op.mDeviceAttributedOps.valueAt(deviceIndex);
- for (int tagIndex = attributedOps.size() - 1; tagIndex >= 0;
- tagIndex--) {
- String tag = attributedOps.keyAt(tagIndex);
- if (attributionTags.contains(tag)) {
- // attribution still exist after upgrade
- continue;
- }
-
- String newAttributionTag = dstAttributionTags.get(tag);
-
- AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
- newAttributionTag,
- op.mDeviceAttributedOps.keyAt(deviceIndex));
- newAttributedOp.add(attributedOps.get(tag));
- attributedOps.remove(tag);
-
- scheduleFastWriteLocked();
- }
- }
- }
+ refreshAttributionsLocked(pkg, uid);
}
}
}
@@ -1136,41 +1074,6 @@
mContext.registerReceiverAsUser(mOnPackageUpdatedReceiver, UserHandle.ALL,
packageUpdateFilter, null, null);
- synchronized (this) {
- for (int uidNum = mUidStates.size() - 1; uidNum >= 0; uidNum--) {
- int uid = mUidStates.keyAt(uidNum);
- UidState uidState = mUidStates.valueAt(uidNum);
-
- String[] pkgsInUid = getPackagesForUid(uidState.uid);
- if (ArrayUtils.isEmpty(pkgsInUid) && uid >= Process.FIRST_APPLICATION_UID) {
- uidState.clear();
- mUidStates.removeAt(uidNum);
- scheduleFastWriteLocked();
- continue;
- }
-
- ArrayMap<String, Ops> pkgs = uidState.pkgOps;
-
- int numPkgs = pkgs.size();
- for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
- String pkg = pkgs.keyAt(pkgNum);
-
- String action;
- if (!ArrayUtils.contains(pkgsInUid, pkg)) {
- action = ACTION_PACKAGE_REMOVED;
- } else {
- action = Intent.ACTION_PACKAGE_REPLACED;
- }
-
- SystemServerInitThreadPool.submit(
- () -> mOnPackageUpdatedReceiver.onReceive(mContext, new Intent(action)
- .setData(Uri.fromParts("package", pkg, null))
- .putExtra(Intent.EXTRA_UID, uid)),
- "Update app-ops uidState in case package " + pkg + " changed");
- }
- }
- }
-
prepareInternalCallbacks();
final IntentFilter packageSuspendFilter = new IntentFilter();
@@ -1258,20 +1161,27 @@
void initializeUidStates() {
UserManagerInternal umi = getUserManagerInternal();
synchronized (this) {
+ SparseBooleanArray knownUids = new SparseBooleanArray();
+
+ for (int uid : NON_PACKAGE_UIDS) {
+ if (!mUidStates.contains(uid)) {
+ mUidStates.put(uid, new UidState(uid));
+ }
+ knownUids.put(uid, true);
+ }
+
int[] userIds = umi.getUserIds();
try (PackageManagerLocal.UnfilteredSnapshot snapshot =
getPackageManagerLocal().withUnfilteredSnapshot()) {
Map<String, PackageState> packageStates = snapshot.getPackageStates();
for (int i = 0; i < userIds.length; i++) {
int userId = userIds[i];
- initializeUserUidStatesLocked(userId, packageStates);
+ initializeUserUidStatesLocked(userId, packageStates, knownUids);
}
- }
- for (int uid : NON_PACKAGE_UIDS) {
- mUidStates.put(uid, new UidState(uid));
+ trimUidStatesLocked(knownUids, packageStates);
+ mUidStatesInitialized = true;
}
- mUidStatesInitialized = true;
}
}
@@ -1279,26 +1189,34 @@
synchronized (this) {
try (PackageManagerLocal.UnfilteredSnapshot snapshot =
getPackageManagerLocal().withUnfilteredSnapshot()) {
- initializeUserUidStatesLocked(userId, snapshot.getPackageStates());
+ initializeUserUidStatesLocked(userId, snapshot.getPackageStates(), null);
}
}
}
private void initializeUserUidStatesLocked(int userId, Map<String,
- PackageState> packageStates) {
+ PackageState> packageStates, SparseBooleanArray knownUids) {
for (Map.Entry<String, PackageState> entry : packageStates.entrySet()) {
- int appId = entry.getValue().getAppId();
+ PackageState packageState = entry.getValue();
+ if (packageState.isApex()) {
+ continue;
+ }
+ int appId = packageState.getAppId();
String packageName = entry.getKey();
- initializePackageUidStateLocked(userId, appId, packageName);
+ initializePackageUidStateLocked(userId, appId, packageName, knownUids);
}
}
/*
Be careful not to clear any existing data; only want to add objects that don't already exist.
*/
- private void initializePackageUidStateLocked(int userId, int appId, String packageName) {
+ private void initializePackageUidStateLocked(int userId, int appId, String packageName,
+ SparseBooleanArray knownUids) {
int uid = UserHandle.getUid(userId, appId);
+ if (knownUids != null) {
+ knownUids.put(uid, true);
+ }
UidState uidState = getUidStateLocked(uid, true);
Ops ops = uidState.pkgOps.get(packageName);
if (ops == null) {
@@ -1316,7 +1234,105 @@
}
}
- createSandboxUidStateIfNotExistsForAppLocked(uid);
+ createSandboxUidStateIfNotExistsForAppLocked(uid, knownUids);
+ }
+
+ private void trimUidStatesLocked(SparseBooleanArray knownUids,
+ Map<String, PackageState> packageStates) {
+ synchronized (this) {
+ // Remove what may have been added during persistence parsing
+ for (int i = mUidStates.size() - 1; i >= 0; i--) {
+ int uid = mUidStates.keyAt(i);
+ if (knownUids.get(uid, false)) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
+ ArrayMap<String, Ops> pkgOps = mUidStates.valueAt(i).pkgOps;
+ for (int j = 0; j < pkgOps.size(); j++) {
+ String pkgName = pkgOps.keyAt(j);
+ if (!packageStates.containsKey(pkgName)) {
+ pkgOps.removeAt(j);
+ continue;
+ }
+ AndroidPackage pkg = packageStates.get(pkgName).getAndroidPackage();
+ if (pkg != null) {
+ refreshAttributionsLocked(pkg, uid);
+ }
+ }
+ if (pkgOps.isEmpty()) {
+ mUidStates.remove(i);
+ }
+ }
+ } else {
+ mUidStates.removeAt(i);
+ }
+ }
+ }
+ }
+
+ @GuardedBy("this")
+ private void refreshAttributionsLocked(AndroidPackage pkg, int uid) {
+ String pkgName = pkg.getPackageName();
+ ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
+ ArraySet<String> attributionTags = new ArraySet<>();
+ attributionTags.add(null);
+ if (pkg.getAttributions() != null) {
+ int numAttributions = pkg.getAttributions().size();
+ for (int attributionNum = 0; attributionNum < numAttributions;
+ attributionNum++) {
+ ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
+ attributionTags.add(attribution.getTag());
+
+ int numInheritFrom = attribution.getInheritFrom().size();
+ for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
+ inheritFromNum++) {
+ dstAttributionTags.put(attribution.getInheritFrom().get(inheritFromNum),
+ attribution.getTag());
+ }
+ }
+ }
+
+ UidState uidState = mUidStates.get(uid);
+ if (uidState == null) {
+ return;
+ }
+
+ Ops ops = uidState.pkgOps.get(pkgName);
+ if (ops == null) {
+ return;
+ }
+
+ // Reset cached package properties to re-initialize when needed
+ ops.bypass = null;
+ ops.knownAttributionTags.clear();
+
+ // Merge data collected for removed attributions into their successor
+ // attributions
+ int numOps = ops.size();
+ for (int opNum = 0; opNum < numOps; opNum++) {
+ Op op = ops.valueAt(opNum);
+ for (int deviceIndex = op.mDeviceAttributedOps.size() - 1; deviceIndex >= 0;
+ deviceIndex--) {
+ ArrayMap<String, AttributedOp> attributedOps =
+ op.mDeviceAttributedOps.valueAt(deviceIndex);
+ for (int tagIndex = attributedOps.size() - 1; tagIndex >= 0;
+ tagIndex--) {
+ String tag = attributedOps.keyAt(tagIndex);
+ if (attributionTags.contains(tag)) {
+ // attribution still exist after upgrade
+ continue;
+ }
+
+ String newAttributionTag = dstAttributionTags.get(tag);
+
+ AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
+ newAttributionTag,
+ op.mDeviceAttributedOps.keyAt(deviceIndex));
+ newAttributedOp.add(attributedOps.get(tag));
+ attributedOps.remove(tag);
+
+ scheduleFastWriteLocked();
+ }
+ }
+ }
}
/**
@@ -4251,8 +4267,15 @@
return uidState;
}
- private void createSandboxUidStateIfNotExistsForAppLocked(int uid) {
+ private void createSandboxUidStateIfNotExistsForAppLocked(int uid,
+ SparseBooleanArray knownUids) {
+ if (UserHandle.getAppId(uid) < Process.FIRST_APPLICATION_UID) {
+ return;
+ }
final int sandboxUid = Process.toSdkSandboxUid(uid);
+ if (knownUids != null) {
+ knownUids.put(sandboxUid, true);
+ }
getUidStateLocked(sandboxUid, true);
}
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
index 23a384f..bc6ef20 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -16,6 +16,7 @@
package com.android.server.appop;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
@@ -30,6 +31,7 @@
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_TAKE_AUDIO_FOCUS;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
import static android.app.AppOpsManager.UID_STATE_TOP;
@@ -139,7 +141,6 @@
}
private int evalModeInternal(int uid, int code, int uidState, int uidCapability) {
-
if (getUidAppWidgetVisible(uid) || mActivityManagerInternal.isPendingTopUid(uid)
|| mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(uid)) {
return MODE_ALLOWED;
@@ -173,6 +174,8 @@
case OP_RECORD_AUDIO:
case OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO:
return PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+ case OP_TAKE_AUDIO_FOCUS:
+ return PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
default:
return PROCESS_CAPABILITY_NONE;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c59f4f7..559a1d6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -34,6 +34,7 @@
import static android.media.audio.Flags.automaticBtDeviceType;
import static android.media.audio.Flags.featureSpatialAudioHeadtrackingLowLatency;
import static android.media.audio.Flags.focusFreezeTestApi;
+import static android.media.audio.Flags.foregroundAudioControl;
import static android.media.audiopolicy.Flags.enableFadeManagerConfiguration;
import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.INVALID_UID;
@@ -1356,7 +1357,8 @@
mMusicFxHelper = new MusicFxHelper(mContext, mAudioHandler);
- mHardeningEnforcer = new HardeningEnforcer(mContext, isPlatformAutomotive());
+ mHardeningEnforcer = new HardeningEnforcer(mContext, isPlatformAutomotive(), mAppOps,
+ context.getPackageManager());
}
private void initVolumeStreamStates() {
@@ -4517,7 +4519,8 @@
}
private void dumpFlags(PrintWriter pw) {
- pw.println("\nFun with Flags: ");
+
+ pw.println("\nFun with Flags:");
pw.println("\tandroid.media.audio.autoPublicVolumeApiHardening:"
+ autoPublicVolumeApiHardening());
pw.println("\tandroid.media.audio.Flags.automaticBtDeviceType:"
@@ -4528,8 +4531,8 @@
+ focusFreezeTestApi());
pw.println("\tcom.android.media.audio.disablePrescaleAbsoluteVolume:"
+ disablePrescaleAbsoluteVolume());
- pw.println("\tandroid.media.audiopolicy.enableFadeManagerConfiguration:"
- + enableFadeManagerConfiguration());
+ pw.println("\tandroid.media.audio.foregroundAudioControl:"
+ + foregroundAudioControl());
}
private void dumpAudioMode(PrintWriter pw) {
@@ -10175,10 +10178,38 @@
.record();
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
+
+ // does caller have system privileges to bypass HardeningEnforcer
+ boolean permissionOverridesCheck = false;
+ if ((mContext.checkCallingOrSelfPermission(
+ Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ == PackageManager.PERMISSION_GRANTED)
+ || (mContext.checkCallingOrSelfPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
+ == PackageManager.PERMISSION_GRANTED)) {
+ permissionOverridesCheck = true;
+ } else if (uid < UserHandle.AID_APP_START) {
+ permissionOverridesCheck = true;
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!permissionOverridesCheck && mHardeningEnforcer.blockFocusMethod(uid,
+ HardeningEnforcer.METHOD_AUDIO_MANAGER_REQUEST_AUDIO_FOCUS,
+ clientId, durationHint, callingPackageName)) {
+ final String reason = "Audio focus request blocked by hardening";
+ Log.w(TAG, reason);
+ mmi.set(MediaMetrics.Property.EARLY_RETURN, reason).record();
+ return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
mmi.record();
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
clientId, callingPackageName, attributionTag, flags, sdk,
- forceFocusDuckingForAccessibility(aa, durationHint, uid), -1 /*testUid, ignored*/);
+ forceFocusDuckingForAccessibility(aa, durationHint, uid), -1 /*testUid, ignored*/,
+ permissionOverridesCheck);
}
/** see {@link AudioManager#requestAudioFocusForTest(AudioFocusRequest, String, int, int)} */
@@ -10195,7 +10226,7 @@
}
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
clientId, callingPackageName, null, flags,
- sdk, false /*forceDuck*/, fakeUid);
+ sdk, false /*forceDuck*/, fakeUid, true /*permissionOverridesCheck*/);
}
public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa,
@@ -11639,6 +11670,7 @@
pw.println("\nMessage handler is null");
}
dumpFlags(pw);
+ mHardeningEnforcer.dump(pw);
mMediaFocusControl.dump(pw);
dumpStreamStates(pw);
dumpVolumeGroups(pw);
diff --git a/services/core/java/com/android/server/audio/HardeningEnforcer.java b/services/core/java/com/android/server/audio/HardeningEnforcer.java
index 4ceb83b2..409ed17 100644
--- a/services/core/java/com/android/server/audio/HardeningEnforcer.java
+++ b/services/core/java/com/android/server/audio/HardeningEnforcer.java
@@ -18,13 +18,21 @@
import static android.media.audio.Flags.autoPublicVolumeApiHardening;
import android.Manifest;
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Binder;
import android.os.UserHandle;
import android.text.TextUtils;
-import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.utils.EventLogger;
+
+import java.io.PrintWriter;
/**
* Class to encapsulate all audio API hardening operations
@@ -32,10 +40,19 @@
public class HardeningEnforcer {
private static final String TAG = "AS.HardeningEnforcer";
+ private static final boolean DEBUG = false;
+ private static final int LOG_NB_EVENTS = 20;
final Context mContext;
+ final AppOpsManager mAppOps;
final boolean mIsAutomotive;
+ final ActivityManager mActivityManager;
+ final PackageManager mPackageManager;
+
+ final EventLogger mEventLogger = new EventLogger(LOG_NB_EVENTS,
+ "Hardening enforcement");
+
/**
* Matches calls from {@link AudioManager#setStreamVolume(int, int, int)}
*/
@@ -56,10 +73,24 @@
* Matches calls from {@link AudioManager#setRingerMode(int)}
*/
public static final int METHOD_AUDIO_MANAGER_SET_RINGER_MODE = 200;
+ /**
+ * Matches calls from {@link AudioManager#requestAudioFocus(AudioFocusRequest)}
+ * and legacy variants
+ */
+ public static final int METHOD_AUDIO_MANAGER_REQUEST_AUDIO_FOCUS = 300;
- public HardeningEnforcer(Context ctxt, boolean isAutomotive) {
+ public HardeningEnforcer(Context ctxt, boolean isAutomotive, AppOpsManager appOps,
+ PackageManager pm) {
mContext = ctxt;
mIsAutomotive = isAutomotive;
+ mAppOps = appOps;
+ mActivityManager = ctxt.getSystemService(ActivityManager.class);
+ mPackageManager = pm;
+ }
+
+ protected void dump(PrintWriter pw) {
+ // log
+ mEventLogger.dump(pw);
}
/**
@@ -84,7 +115,7 @@
}
// TODO metrics?
// TODO log for audio dumpsys?
- Log.e(TAG, "Preventing volume method " + volumeMethod + " for "
+ Slog.e(TAG, "Preventing volume method " + volumeMethod + " for "
+ getPackNameForUid(Binder.getCallingUid()));
return true;
}
@@ -92,10 +123,40 @@
return false;
}
+ /**
+ * Checks whether the call in the current thread should be allowed or blocked
+ * @param focusMethod name of the method to check, for logging purposes
+ * @param clientId id of the requester
+ * @param durationHint focus type being requested
+ * @return false if the method call is allowed, true if it should be a no-op
+ */
+ protected boolean blockFocusMethod(int callingUid, int focusMethod, @NonNull String clientId,
+ int durationHint, @NonNull String packageName) {
+ if (packageName.isEmpty()) {
+ packageName = getPackNameForUid(callingUid);
+ }
+
+ if (checkAppOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, callingUid, packageName)) {
+ if (DEBUG) {
+ Slog.i(TAG, "blockFocusMethod pack:" + packageName + " NOT blocking");
+ }
+ return false;
+ }
+
+ String errorMssg = "Focus request DENIED for uid:" + callingUid
+ + " clientId:" + clientId + " req:" + durationHint
+ + " procState:" + mActivityManager.getUidProcessState(callingUid);
+
+ // TODO metrics
+ mEventLogger.enqueueAndSlog(errorMssg, EventLogger.Event.ALOGI, TAG);
+
+ return true;
+ }
+
private String getPackNameForUid(int uid) {
final long token = Binder.clearCallingIdentity();
try {
- final String[] names = mContext.getPackageManager().getPackagesForUid(uid);
+ final String[] names = mPackageManager.getPackagesForUid(uid);
if (names == null
|| names.length == 0
|| TextUtils.isEmpty(names[0])) {
@@ -106,4 +167,18 @@
Binder.restoreCallingIdentity(token);
}
}
+
+ /**
+ * Checks the given op without throwing
+ * @param op the appOp code
+ * @param uid the calling uid
+ * @param packageName the package name of the caller
+ * @return return false if the operation is not allowed
+ */
+ private boolean checkAppOp(int op, int uid, @NonNull String packageName) {
+ if (mAppOps.checkOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 1376bde..35d38e2 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -1090,11 +1090,14 @@
* accessibility.
* @param testUid ignored if flags doesn't contain AudioManager.AUDIOFOCUS_FLAG_TEST
* otherwise the UID being injected for testing
+ * @param permissionOverridesCheck true if permission checks guaranteed that the call should
+ * go through, false otherwise (e.g. non-privileged caller)
* @return
*/
protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb,
IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName,
- String attributionTag, int flags, int sdk, boolean forceDuck, int testUid) {
+ String attributionTag, int flags, int sdk, boolean forceDuck, int testUid,
+ boolean permissionOverridesCheck) {
new MediaMetrics.Item(mMetricsId)
.setUid(Binder.getCallingUid())
.set(MediaMetrics.Property.CALLING_PACKAGE, callingPackageName)
@@ -1126,10 +1129,9 @@
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
- if ((flags != AudioManager.AUDIOFOCUS_FLAG_TEST)
- // note we're using the real uid for appOp evaluation
- && (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
- callingPackageName, attributionTag, null) != AppOpsManager.MODE_ALLOWED)) {
+ final int res = mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
+ callingPackageName, attributionTag, null);
+ if (!permissionOverridesCheck && res != AppOpsManager.MODE_ALLOWED) {
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index cd064ae..38051c1 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -21,8 +21,8 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.devicestate.DeviceState.FLAG_CANCEL_OVERRIDE_REQUESTS;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
+import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE_IDENTIFIER;
+import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE_IDENTIFIER;
import static com.android.server.devicestate.OverrideRequest.OVERRIDE_REQUEST_TYPE_BASE_STATE;
import static com.android.server.devicestate.OverrideRequest.OVERRIDE_REQUEST_TYPE_EMULATED_STATE;
@@ -1065,7 +1065,8 @@
}
private final class DeviceStateProviderListener implements DeviceStateProvider.Listener {
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int mCurrentBaseState;
+ @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to = MAXIMUM_DEVICE_STATE_IDENTIFIER)
+ int mCurrentBaseState;
@Override
public void onSupportedDeviceStatesChanged(DeviceState[] newDeviceStates,
@@ -1078,8 +1079,10 @@
@Override
public void onStateChanged(
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier) {
- if (identifier < MINIMUM_DEVICE_STATE || identifier > MAXIMUM_DEVICE_STATE) {
+ @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to =
+ MAXIMUM_DEVICE_STATE_IDENTIFIER) int identifier) {
+ if (identifier < MINIMUM_DEVICE_STATE_IDENTIFIER
+ || identifier > MAXIMUM_DEVICE_STATE_IDENTIFIER) {
throw new IllegalArgumentException("Invalid identifier: " + identifier);
}
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateProvider.java b/services/core/java/com/android/server/devicestate/DeviceStateProvider.java
index 65b393a..b865c1d9 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateProvider.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateProvider.java
@@ -16,8 +16,8 @@
package com.android.server.devicestate;
-import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
+import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE_IDENTIFIER;
+import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE_IDENTIFIER;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -133,10 +133,12 @@
*
* @param identifier the identifier of the new device state.
*
- * @throws IllegalArgumentException if the state is less than {@link MINIMUM_DEVICE_STATE}
- * or greater than {@link MAXIMUM_DEVICE_STATE}.
+ * @throws IllegalArgumentException if the state is less than
+ * {@link MINIMUM_DEVICE_STATE_IDENTIFIER} or greater than
+ * {@link MAXIMUM_DEVICE_STATE_IDENTIFIER}.
*/
void onStateChanged(
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier);
+ @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to =
+ MAXIMUM_DEVICE_STATE_IDENTIFIER) int identifier);
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 4bb8e19..bc169ca 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2901,16 +2901,12 @@
@GuardedBy("ImfLock.class")
void clearClientSessionsLocked() {
if (getCurMethodLocked() != null) {
- // TODO(b/322816970): Replace this with lambda.
- mClientController.forAllClients(new Consumer<ClientState>() {
-
- @GuardedBy("ImfLock.class")
- @Override
- public void accept(ClientState c) {
- clearClientSessionLocked(c);
- clearClientSessionForAccessibilityLocked(c);
- }
- });
+ // TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
+ @SuppressWarnings("GuardedBy") Consumer<ClientState> clearClientSession = c -> {
+ clearClientSessionLocked(c);
+ clearClientSessionForAccessibilityLocked(c);
+ };
+ mClientController.forAllClients(clearClientSession);
finishSessionLocked(mEnabledSession);
for (int i = 0; i < mEnabledAccessibilitySessions.size(); i++) {
@@ -4653,15 +4649,7 @@
super.startImeTrace_enforcePermission();
ImeTracing.getInstance().startTrace(null /* printwriter */);
synchronized (ImfLock.class) {
- // TODO(b/322816970): Replace this with lambda.
- mClientController.forAllClients(new Consumer<ClientState>() {
-
- @GuardedBy("ImfLock.class")
- @Override
- public void accept(ClientState c) {
- c.mClient.setImeTraceEnabled(true /* enabled */);
- }
- });
+ mClientController.forAllClients(c -> c.mClient.setImeTraceEnabled(true /* enabled */));
}
}
@@ -4673,15 +4661,7 @@
ImeTracing.getInstance().stopTrace(null /* printwriter */);
synchronized (ImfLock.class) {
- // TODO(b/322816970): Replace this with lambda.
- mClientController.forAllClients(new Consumer<ClientState>() {
-
- @GuardedBy("ImfLock.class")
- @Override
- public void accept(ClientState c) {
- c.mClient.setImeTraceEnabled(false /* enabled */);
- }
- });
+ mClientController.forAllClients(c -> c.mClient.setImeTraceEnabled(false /* enabled */));
}
}
@@ -5916,15 +5896,12 @@
// We only have sessions when we bound to an input method. Remove this session
// from all clients.
if (getCurMethodLocked() != null) {
- // TODO(b/322816970): Replace this with lambda.
- mClientController.forAllClients(new Consumer<ClientState>() {
+ // TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
+ @SuppressWarnings("GuardedBy") Consumer<ClientState> clearClientSession =
+ c -> clearClientSessionForAccessibilityLocked(c,
+ accessibilityConnectionId);
+ mClientController.forAllClients(clearClientSession);
- @GuardedBy("ImfLock.class")
- @Override
- public void accept(ClientState c) {
- clearClientSessionForAccessibilityLocked(c, accessibilityConnectionId);
- }
- });
AccessibilitySessionState session = mEnabledAccessibilitySessions.get(
accessibilityConnectionId);
if (session != null) {
@@ -6126,24 +6103,21 @@
}
// Dump ClientController#mClients
p.println(" ClientStates:");
- // TODO(b/322816970): Replace this with lambda.
- mClientController.forAllClients(new Consumer<ClientState>() {
+ // TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
+ @SuppressWarnings("GuardedBy") Consumer<ClientState> clientControllerDump = c -> {
+ p.println(" " + c + ":");
+ p.println(" client=" + c.mClient);
+ p.println(" fallbackInputConnection="
+ + c.mFallbackInputConnection);
+ p.println(" sessionRequested="
+ + c.mSessionRequested);
+ p.println(
+ " sessionRequestedForAccessibility="
+ + c.mSessionRequestedForAccessibility);
+ p.println(" curSession=" + c.mCurSession);
+ };
+ mClientController.forAllClients(clientControllerDump);
- @GuardedBy("ImfLock.class")
- @Override
- public void accept(ClientState c) {
- p.println(" " + c + ":");
- p.println(" client=" + c.mClient);
- p.println(" fallbackInputConnection="
- + c.mFallbackInputConnection);
- p.println(" sessionRequested="
- + c.mSessionRequested);
- p.println(
- " sessionRequestedForAccessibility="
- + c.mSessionRequestedForAccessibility);
- p.println(" curSession=" + c.mCurSession);
- }
- });
p.println(" mCurMethodId=" + getSelectedMethodIdLocked());
client = mCurClient;
p.println(" mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked());
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 1546895..bbb19e3 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -550,8 +550,8 @@
break;
case RECORD_CONTENT_TASK:
IBinder taskWindowContainerToken =
- mProjectionGrant.getLaunchCookieInternal() == null ? null
- : mProjectionGrant.getLaunchCookieInternal().binder;
+ mProjectionGrant.getLaunchCookie() == null ? null
+ : mProjectionGrant.getLaunchCookie().binder;
setReviewedConsentSessionLocked(
ContentRecordingSession.createTaskSession(taskWindowContainerToken));
break;
@@ -603,17 +603,6 @@
return projection;
}
- /**
- * Test API mirroring the types in the aidl interface for access outside the projection
- * package.
- */
- @VisibleForTesting
- public IMediaProjection createProjectionInternal(int processUid, String packageName, int type,
- boolean isPermanentGrant) {
- return createProjectionInternal(processUid, packageName, type, isPermanentGrant,
- Binder.getCallingUserHandle());
- }
-
// TODO(b/261563516): Remove internal method and test aidl directly, here and elsewhere.
@VisibleForTesting
MediaProjection getProjectionInternal(int uid, String packageName) {
@@ -1203,10 +1192,6 @@
@Override // Binder call
public void setLaunchCookie(LaunchCookie launchCookie) {
setLaunchCookie_enforcePermission();
- setLaunchCookieInternal(launchCookie);
- }
-
- @VisibleForTesting void setLaunchCookieInternal(LaunchCookie launchCookie) {
mLaunchCookie = launchCookie;
}
@@ -1214,10 +1199,6 @@
@Override // Binder call
public LaunchCookie getLaunchCookie() {
getLaunchCookie_enforcePermission();
- return getLaunchCookieInternal();
- }
-
- @VisibleForTesting LaunchCookie getLaunchCookieInternal() {
return mLaunchCookie;
}
@@ -1225,11 +1206,6 @@
@Override
public boolean isValid() {
isValid_enforcePermission();
- return isValidInternal();
- }
-
- @VisibleForTesting
- boolean isValidInternal() {
synchronized (mLock) {
final long curMs = mClock.uptimeMillis();
final boolean hasTimedOut = curMs - mCreateTimeMs > mTimeoutMs;
@@ -1260,11 +1236,6 @@
@Override
public void notifyVirtualDisplayCreated(int displayId) {
notifyVirtualDisplayCreated_enforcePermission();
- notifyVirtualDisplayCreatedInternal(displayId);
- }
-
- @VisibleForTesting
- void notifyVirtualDisplayCreatedInternal(int displayId) {
synchronized (mLock) {
mVirtualDisplayId = displayId;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index d987622..8729522 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -1143,10 +1143,9 @@
};
private static final class PackageManagerHelperImpl implements PackageManagerHelper {
- private static final class PackageStateUsers {
+ private static class PackageStateUsers {
private PackageState mPackageState;
- private Boolean mDefinesOverlayable = null;
- private final ArraySet<Integer> mInstalledUsers = new ArraySet<>();
+ private final Set<Integer> mInstalledUsers = new ArraySet<>();
private PackageStateUsers(@NonNull PackageState packageState) {
this.mPackageState = packageState;
}
@@ -1196,11 +1195,13 @@
return userPackages;
}
- private PackageStateUsers getRawPackageStateForUser(@NonNull final String packageName,
+ @Override
+ @Nullable
+ public PackageState getPackageStateForUser(@NonNull final String packageName,
final int userId) {
final PackageStateUsers pkg = mCache.get(packageName);
if (pkg != null && pkg.mInstalledUsers.contains(userId)) {
- return pkg;
+ return pkg.mPackageState;
}
try {
if (!mPackageManager.isPackageAvailable(packageName, userId)) {
@@ -1214,14 +1215,8 @@
return addPackageUser(packageName, userId);
}
- @Override
- public PackageState getPackageStateForUser(@NonNull final String packageName,
- final int userId) {
- final PackageStateUsers pkg = getRawPackageStateForUser(packageName, userId);
- return pkg != null ? pkg.mPackageState : null;
- }
-
- private PackageStateUsers addPackageUser(@NonNull final String packageName,
+ @NonNull
+ private PackageState addPackageUser(@NonNull final String packageName,
final int user) {
final PackageState pkg = mPackageManagerInternal.getPackageStateInternal(packageName);
if (pkg == null) {
@@ -1233,20 +1228,20 @@
}
@NonNull
- private PackageStateUsers addPackageUser(@NonNull final PackageState pkg,
+ private PackageState addPackageUser(@NonNull final PackageState pkg,
final int user) {
PackageStateUsers pkgUsers = mCache.get(pkg.getPackageName());
if (pkgUsers == null) {
pkgUsers = new PackageStateUsers(pkg);
mCache.put(pkg.getPackageName(), pkgUsers);
- } else if (pkgUsers.mPackageState != pkg) {
+ } else {
pkgUsers.mPackageState = pkg;
- pkgUsers.mDefinesOverlayable = null;
}
pkgUsers.mInstalledUsers.add(user);
- return pkgUsers;
+ return pkgUsers.mPackageState;
}
+
@NonNull
private void removePackageUser(@NonNull final String packageName, final int user) {
final PackageStateUsers pkgUsers = mCache.get(packageName);
@@ -1264,15 +1259,15 @@
}
}
+ @Nullable
public PackageState onPackageAdded(@NonNull final String packageName, final int userId) {
- final var pu = addPackageUser(packageName, userId);
- return pu != null ? pu.mPackageState : null;
+ return addPackageUser(packageName, userId);
}
+ @Nullable
public PackageState onPackageUpdated(@NonNull final String packageName,
final int userId) {
- final var pu = addPackageUser(packageName, userId);
- return pu != null ? pu.mPackageState : null;
+ return addPackageUser(packageName, userId);
}
public void onPackageRemoved(@NonNull final String packageName, final int userId) {
@@ -1312,30 +1307,22 @@
return (pkgs.length == 0) ? null : pkgs[0];
}
+ @Nullable
@Override
public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
@NonNull String targetOverlayableName, int userId)
throws IOException {
- final var psu = getRawPackageStateForUser(packageName, userId);
- final var pkg = (psu == null || psu.mPackageState == null)
- ? null : psu.mPackageState.getAndroidPackage();
+ var packageState = getPackageStateForUser(packageName, userId);
+ var pkg = packageState == null ? null : packageState.getAndroidPackage();
if (pkg == null) {
throw new IOException("Unable to get target package");
}
- if (Boolean.FALSE.equals(psu.mDefinesOverlayable)) {
- return null;
- }
-
ApkAssets apkAssets = null;
try {
apkAssets = ApkAssets.loadFromPath(pkg.getSplits().get(0).getPath(),
ApkAssets.PROPERTY_ONLY_OVERLAYABLES);
- if (psu.mDefinesOverlayable == null) {
- psu.mDefinesOverlayable = apkAssets.definesOverlayable();
- }
- return Boolean.FALSE.equals(psu.mDefinesOverlayable)
- ? null : apkAssets.getOverlayableInfo(targetOverlayableName);
+ return apkAssets.getOverlayableInfo(targetOverlayableName);
} finally {
if (apkAssets != null) {
try {
@@ -1349,29 +1336,24 @@
@Override
public boolean doesTargetDefineOverlayable(String targetPackageName, int userId)
throws IOException {
- final var psu = getRawPackageStateForUser(targetPackageName, userId);
- var pkg = (psu == null || psu.mPackageState == null)
- ? null : psu.mPackageState.getAndroidPackage();
+ var packageState = getPackageStateForUser(targetPackageName, userId);
+ var pkg = packageState == null ? null : packageState.getAndroidPackage();
if (pkg == null) {
throw new IOException("Unable to get target package");
}
- if (psu.mDefinesOverlayable == null) {
- ApkAssets apkAssets = null;
- try {
- apkAssets = ApkAssets.loadFromPath(pkg.getSplits().get(0).getPath(),
- ApkAssets.PROPERTY_ONLY_OVERLAYABLES);
- psu.mDefinesOverlayable = apkAssets.definesOverlayable();
- } finally {
- if (apkAssets != null) {
- try {
- apkAssets.close();
- } catch (Throwable ignored) {
- }
+ ApkAssets apkAssets = null;
+ try {
+ apkAssets = ApkAssets.loadFromPath(pkg.getSplits().get(0).getPath());
+ return apkAssets.definesOverlayable();
+ } finally {
+ if (apkAssets != null) {
+ try {
+ apkAssets.close();
+ } catch (Throwable ignored) {
}
}
}
- return psu.mDefinesOverlayable;
}
@Override
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OWNERS b/services/core/java/com/android/server/ondeviceintelligence/OWNERS
new file mode 100644
index 0000000..09774f7
--- /dev/null
+++ b/services/core/java/com/android/server/ondeviceintelligence/OWNERS
@@ -0,0 +1 @@
+file:/core/java/android/app/ondeviceintelligence/OWNERS
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 85d2df3..bbce26c 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -27,11 +27,14 @@
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.Flags;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
+import android.os.SystemProperties;
import android.os.Trace;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -50,9 +53,15 @@
import java.io.File;
import java.io.IOException;
+import java.util.Set;
final class PackageAbiHelperImpl implements PackageAbiHelper {
+ @Nullable
+ private static String[] sNativelySupported32BitAbis = null;
+ @Nullable
+ private static String[] sNativelySupported64BitAbis = null;
+
private static String calculateBundledApkRoot(final String codePathString) {
final File codePath = new File(codePathString);
final File codeRoot;
@@ -122,13 +131,20 @@
}
}
- private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
- PackageManagerException {
+ private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet,
+ boolean forceMatch) throws PackageManagerException {
if (copyRet < 0) {
if (copyRet != PackageManager.NO_NATIVE_LIBRARIES
&& copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
throw new PackageManagerException(copyRet, message);
}
+
+ if (forceMatch && copyRet == PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_MULTI_ARCH_NOT_MATCH_ALL_NATIVE_ABIS,
+ "The multiArch app's native libs don't support all the natively"
+ + " supported ABIs of the device.");
+ }
}
}
@@ -296,7 +312,40 @@
return new Abis(primaryCpuAbi, secondaryCpuAbi);
}
+ @NonNull
+ private static String[] getNativelySupportedAbis(@NonNull String[] supportedAbis) {
+ Set<String> nativelySupportedAbis = new ArraySet<>();
+ for (int i = 0; i < supportedAbis.length; i++) {
+ final String currentAbi = supportedAbis[i];
+ // In presence of a native bridge this means the Abi is emulated.
+ final String currentIsa = VMRuntime.getInstructionSet(currentAbi);
+ if (TextUtils.isEmpty(SystemProperties.get("ro.dalvik.vm.isa." + currentIsa))) {
+ nativelySupportedAbis.add(currentAbi);
+ }
+ }
+ return nativelySupportedAbis.toArray(new String[0]);
+ }
+
+ private static String[] getNativelySupported32BitAbis() {
+ if (sNativelySupported32BitAbis != null) {
+ return sNativelySupported32BitAbis;
+ }
+
+ sNativelySupported32BitAbis = getNativelySupportedAbis(Build.SUPPORTED_32_BIT_ABIS);
+ return sNativelySupported32BitAbis;
+ }
+
+ private static String[] getNativelySupported64BitAbis() {
+ if (sNativelySupported64BitAbis != null) {
+ return sNativelySupported64BitAbis;
+ }
+
+ sNativelySupported64BitAbis = getNativelySupportedAbis(Build.SUPPORTED_64_BIT_ABIS);
+ return sNativelySupported64BitAbis;
+ }
+
@Override
+ @SuppressWarnings("AndroidFrameworkCompatChange") // the check is before the apk is installed
public Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg, boolean isSystemApp,
boolean isUpdatedSystemApp, String cpuAbiOverride, File appLib32InstallDir)
throws PackageManagerException {
@@ -334,18 +383,33 @@
primaryCpuAbi = null;
secondaryCpuAbi = null;
if (pkg.isMultiArch()) {
+ // Force the match for these cases
+ // 1. pkg.getTargetSdkVersion >= Build.VERSION_CODES.VANILLA_ICE_CREAM
+ // 2. cpuAbiOverride is null. If it is non-null, it is set via shell for testing
+ final boolean forceMatch = Flags.forceMultiArchNativeLibsMatch()
+ && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.VANILLA_ICE_CREAM
+ && cpuAbiOverride == null;
+
+ String[] supported32BitAbis = forceMatch ? getNativelySupported32BitAbis()
+ : Build.SUPPORTED_32_BIT_ABIS;
+ String[] supported64BitAbis = forceMatch ? getNativelySupported64BitAbis()
+ : Build.SUPPORTED_64_BIT_ABIS;
+
+ final boolean systemSupports32BitAbi = supported32BitAbis.length > 0;
+ final boolean systemSupports64BitAbi = supported64BitAbis.length > 0;
+
int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
- if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+ if (systemSupports32BitAbi) {
if (extractLibs) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+ nativeLibraryRoot, supported32BitAbis,
useIsaSpecificSubdirs, onIncremental);
} else {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
abi32 = NativeLibraryHelper.findSupportedAbi(
- handle, Build.SUPPORTED_32_BIT_ABIS);
+ handle, supported32BitAbis);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -357,24 +421,26 @@
}
maybeThrowExceptionForMultiArchCopy(
- "Error unpackaging 32 bit native libs for multiarch app.", abi32);
+ "Error unpackaging 32 bit native libs for multiarch app.", abi32,
+ forceMatch && systemSupports32BitAbi);
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+ if (systemSupports64BitAbi) {
if (extractLibs) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+ nativeLibraryRoot, supported64BitAbis,
useIsaSpecificSubdirs, onIncremental);
} else {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
abi64 = NativeLibraryHelper.findSupportedAbi(
- handle, Build.SUPPORTED_64_BIT_ABIS);
+ handle, supported64BitAbis);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
maybeThrowExceptionForMultiArchCopy(
- "Error unpackaging 64 bit native libs for multiarch app.", abi64);
+ "Error unpackaging 64 bit native libs for multiarch app.", abi64,
+ forceMatch && systemSupports64BitAbi);
if (abi64 >= 0) {
// Shared library native libs should be in the APK zip aligned
@@ -382,11 +448,11 @@
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Shared library native lib extraction not supported");
}
- primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
+ primaryCpuAbi = supported64BitAbis[abi64];
}
if (abi32 >= 0) {
- final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
+ final String abi = supported32BitAbis[abi32];
if (abi64 >= 0) {
if (pkg.is32BitAbiPreferred()) {
secondaryCpuAbi = primaryCpuAbi;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index f44fcf0..21e2bf2 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -42,6 +42,7 @@
import android.app.AppOpsManager;
import android.app.AppOpsManager.AttributionFlags;
import android.app.IActivityManager;
+import android.companion.virtual.VirtualDeviceManager;
import android.content.AttributionSource;
import android.content.AttributionSourceState;
import android.content.Context;
@@ -78,6 +79,7 @@
import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.TriFunction;
import com.android.server.LocalServices;
+import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal.HotwordDetectionServiceProvider;
import com.android.server.pm.pkg.AndroidPackage;
@@ -135,6 +137,9 @@
@Nullable
private HotwordDetectionServiceProvider mHotwordDetectionServiceProvider;
+ @Nullable
+ private VirtualDeviceManagerInternal mVirtualDeviceManagerInternal;
+
PermissionManagerService(@NonNull Context context,
@NonNull ArrayMap<String, FeatureInfo> availableFeatures) {
// The package info cache is the cache for package and permission information.
@@ -146,6 +151,8 @@
mContext = context;
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
+ mVirtualDeviceManagerInternal =
+ LocalServices.getService(VirtualDeviceManagerInternal.class);
mAttributionSourceRegistry = new AttributionSourceRegistry(context);
@@ -246,16 +253,30 @@
return PackageManager.PERMISSION_DENIED;
}
+ String persistentDeviceId = getPersistentDeviceId(deviceId);
+
final CheckPermissionDelegate checkPermissionDelegate;
synchronized (mLock) {
checkPermissionDelegate = mCheckPermissionDelegate;
}
-
- if (checkPermissionDelegate == null) {
- return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName, deviceId);
+ if (checkPermissionDelegate == null) {
+ return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName,
+ persistentDeviceId);
}
return checkPermissionDelegate.checkUidPermission(uid, permissionName,
- deviceId, mPermissionManagerServiceImpl::checkUidPermission);
+ persistentDeviceId, mPermissionManagerServiceImpl::checkUidPermission);
+ }
+
+ private String getPersistentDeviceId(int deviceId) {
+ if (deviceId == Context.DEVICE_ID_DEFAULT) {
+ return VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT;
+ }
+
+ if (mVirtualDeviceManagerInternal == null) {
+ mVirtualDeviceManagerInternal =
+ LocalServices.getService(VirtualDeviceManagerInternal.class);
+ }
+ return mVirtualDeviceManagerInternal.getPersistentIdForDevice(deviceId);
}
@Override
@@ -608,15 +629,17 @@
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
int deviceId, int userId) {
+ String persistentDeviceId = getPersistentDeviceId(deviceId);
return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
- permissionName, deviceId, userId);
+ permissionName, persistentDeviceId, userId);
}
@Override
public boolean isPermissionRevokedByPolicy(String packageName, String permissionName,
int deviceId, int userId) {
+ String persistentDeviceId = getPersistentDeviceId(deviceId);
return mPermissionManagerServiceImpl.isPermissionRevokedByPolicy(packageName,
- permissionName, deviceId, userId);
+ permissionName, persistentDeviceId, userId);
}
@Override
@@ -914,13 +937,13 @@
*
* @param uid the UID to be checked
* @param permissionName the name of the permission to be checked
- * @param deviceId The device ID
+ * @param persistentDeviceId The persistent device ID
* @param superImpl the original implementation that can be delegated to
* @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has
* the permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} otherwise
*/
- int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
- TriFunction<Integer, String, Integer, Integer> superImpl);
+ int checkUidPermission(int uid, @NonNull String permissionName, String persistentDeviceId,
+ TriFunction<Integer, String, String, Integer> superImpl);
/**
* @return list of delegated permissions
@@ -965,17 +988,18 @@
}
@Override
- public int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
- @NonNull TriFunction<Integer, String, Integer, Integer> superImpl) {
+ public int checkUidPermission(int uid, @NonNull String permissionName,
+ String persistentDeviceId,
+ @NonNull TriFunction<Integer, String, String, Integer> superImpl) {
if (uid == mDelegatedUid && isDelegatedPermission(permissionName)) {
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(Process.SHELL_UID, permissionName, deviceId);
+ return superImpl.apply(Process.SHELL_UID, permissionName, persistentDeviceId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(uid, permissionName, deviceId);
+ return superImpl.apply(uid, permissionName, persistentDeviceId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index c5b637d..70913c3 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -682,7 +682,7 @@
}
@Override
- public int getPermissionFlags(String packageName, String permName, String persistentDeviceId,
+ public int getPermissionFlags(String packageName, String permName, String deviceId,
int userId) {
final int callingUid = Binder.getCallingUid();
return getPermissionFlagsInternal(packageName, permName, callingUid, userId);
@@ -726,8 +726,7 @@
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, String persistentDeviceId,
- int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, String deviceId, int userId) {
final int callingUid = Binder.getCallingUid();
boolean overridePolicy = false;
@@ -917,8 +916,7 @@
}
@Override
- public int checkPermission(String pkgName, String permName, String persistentDeviceId,
- int userId) {
+ public int checkPermission(String pkgName, String permName, String deviceId, int userId) {
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
}
@@ -985,11 +983,11 @@
}
private int checkUidPermission(int uid, String permName) {
- return checkUidPermission(uid, permName, Context.DEVICE_ID_DEFAULT);
+ return checkUidPermission(uid, permName, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
}
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
+ public int checkUidPermission(int uid, String permName, String deviceId) {
final int userId = UserHandle.getUserId(uid);
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
@@ -1001,7 +999,7 @@
@Override
public Map<String, PermissionManager.PermissionState> getAllPermissionStates(
- @NonNull String packageName, @NonNull String persistentDeviceId, int userId) {
+ @NonNull String packageName, @NonNull String deviceId, int userId) {
throw new UnsupportedOperationException(
"This method is supported in newer implementation only");
}
@@ -1315,8 +1313,8 @@
}
@Override
- public void grantRuntimePermission(String packageName, String permName,
- String persistentDeviceId, int userId) {
+ public void grantRuntimePermission(String packageName, String permName, String deviceId,
+ int userId) {
final int callingUid = Binder.getCallingUid();
final boolean overridePolicy =
checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY)
@@ -1489,12 +1487,13 @@
}
@Override
- public void revokeRuntimePermission(String packageName, String permName,
- String persistentDeviceId, int userId, String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, String deviceId,
+ int userId, String reason) {
final int callingUid = Binder.getCallingUid();
final boolean overridePolicy =
checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY,
- Context.DEVICE_ID_DEFAULT) == PackageManager.PERMISSION_GRANTED;
+ VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)
+ == PackageManager.PERMISSION_GRANTED;
revokeRuntimePermissionInternal(packageName, permName, overridePolicy, callingUid, userId,
reason, mDefaultPermissionCallback);
@@ -1880,7 +1879,7 @@
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, @UserIdInt int userId) {
+ String deviceId, @UserIdInt int userId) {
final int callingUid = Binder.getCallingUid();
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingPermission(
@@ -1943,7 +1942,7 @@
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, String deviceId,
int userId) {
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingPermission(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 7c10425..47032ea 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -141,11 +141,11 @@
*
* @param packageName the package name for which to get the flags
* @param permName the permission for which to get the flags
- * @param persistentDeviceId The device for which to get the flags
+ * @param deviceId The device for which to get the flags
* @param userId the user for which to get permission flags
* @return the permission flags
*/
- int getPermissionFlags(String packageName, String permName, String persistentDeviceId,
+ int getPermissionFlags(String packageName, String permName, String deviceId,
@UserIdInt int userId);
/**
@@ -156,11 +156,11 @@
* @param permName The permission for which to update the flags
* @param flagMask The flags which to replace
* @param flagValues The flags with which to replace
- * @param persistentDeviceId The device for which to update the permission flags
+ * @param deviceId The device for which to update the permission flags
* @param userId The user for which to update the permission flags
*/
void updatePermissionFlags(String packageName, String permName, int flagMask, int flagValues,
- boolean checkAdjustPolicyFlagPermission, String persistentDeviceId,
+ boolean checkAdjustPolicyFlagPermission, String deviceId,
@UserIdInt int userId);
/**
@@ -295,12 +295,12 @@
*
* @param packageName the package to which to grant the permission
* @param permName the permission name to grant
- * @param persistentDeviceId the device for which to grant the permission
+ * @param deviceId the device for which to grant the permission
* @param userId the user for which to grant the permission
*
* @see #revokeRuntimePermission(String, String, String, int, String)
*/
- void grantRuntimePermission(String packageName, String permName, String persistentDeviceId,
+ void grantRuntimePermission(String packageName, String permName, String deviceId,
@UserIdInt int userId);
/**
@@ -316,13 +316,13 @@
*
* @param packageName the package from which to revoke the permission
* @param permName the permission name to revoke
- * @param persistentDeviceId the device for which to revoke the permission
+ * @param deviceId the device for which to revoke the permission
* @param userId the user for which to revoke the permission
* @param reason the reason for the revoke, or {@code null} for unspecified
*
* @see #grantRuntimePermission(String, String, String, int)
*/
- void revokeRuntimePermission(String packageName, String permName, String persistentDeviceId,
+ void revokeRuntimePermission(String packageName, String permName, String deviceId,
@UserIdInt int userId, String reason);
/**
@@ -347,7 +347,7 @@
* @return whether you can show permission rationale UI
*/
boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, @UserIdInt int userId);
+ String deviceId, @UserIdInt int userId);
/**
* Checks whether a particular permission has been revoked for a package by policy. Typically,
@@ -361,8 +361,8 @@
* @param userId the device for which you are checking the permission
* @return whether the permission is restricted by policy
*/
- boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
- @UserIdInt int userId);
+ boolean isPermissionRevokedByPolicy(String packageName, String permName,
+ String deviceId, @UserIdInt int userId);
/**
* Get set of permissions that have been split into more granular or dependent permissions.
@@ -389,11 +389,11 @@
*
* @param pkgName package name
* @param permName permission name
- * @param persistentDeviceId persistent device ID
+ * @param deviceId persistent device ID
* @param userId user ID
* @return permission result {@link PackageManager.PermissionResult}
*/
- int checkPermission(String pkgName, String permName, String persistentDeviceId,
+ int checkPermission(String pkgName, String permName, String deviceId,
@UserIdInt int userId);
/**
@@ -401,23 +401,23 @@
*
* @param uid UID
* @param permName permission name
- * @param deviceId device ID
+ * @param deviceId persistent device ID
* @return permission result {@link PackageManager.PermissionResult}
*/
- int checkUidPermission(int uid, String permName, int deviceId);
+ int checkUidPermission(int uid, String permName, String deviceId);
/**
* Gets the permission states for requested package, persistent device and user.
*
* @param packageName name of the package you are checking against
- * @param persistentDeviceId id of the persistent device you are checking against
+ * @param deviceId id of the persistent device you are checking against
* @param userId id of the user for which to get permission flags
* @return mapping of all permission states keyed by their permission names
*
* @hide
*/
Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
- @NonNull String persistentDeviceId, @UserIdInt int userId);
+ @NonNull String deviceId, @UserIdInt int userId);
/**
* Get all the package names requesting app op permissions.
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
index 91a778d..c18f856 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
@@ -121,24 +121,22 @@
}
@Override
- public int getPermissionFlags(String packageName, String permName, String persistentDeviceId,
+ public int getPermissionFlags(String packageName, String permName, String deviceId,
int userId) {
Log.i(LOG_TAG, "getPermissionFlags(packageName = " + packageName + ", permName = "
- + permName + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId
- + ")");
- return mService.getPermissionFlags(packageName, permName, persistentDeviceId, userId);
+ + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+ return mService.getPermissionFlags(packageName, permName, deviceId, userId);
}
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, String persistentDeviceId,
- int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, String deviceId, int userId) {
Log.i(LOG_TAG, "updatePermissionFlags(packageName = " + packageName + ", permName = "
+ permName + ", flagMask = " + flagMask + ", flagValues = " + flagValues
+ ", checkAdjustPolicyFlagPermission = " + checkAdjustPolicyFlagPermission
- + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId + ")");
+ + ", deviceId = " + deviceId + ", userId = " + userId + ")");
mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, persistentDeviceId, userId);
+ checkAdjustPolicyFlagPermission, deviceId, userId);
}
@Override
@@ -186,21 +184,20 @@
}
@Override
- public void grantRuntimePermission(String packageName, String permName,
- String persistentDeviceId, int userId) {
+ public void grantRuntimePermission(String packageName, String permName, String deviceId,
+ int userId) {
Log.i(LOG_TAG, "grantRuntimePermission(packageName = " + packageName + ", permName = "
- + permName + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId
- + ")");
- mService.grantRuntimePermission(packageName, permName, persistentDeviceId, userId);
+ + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+ mService.grantRuntimePermission(packageName, permName, deviceId, userId);
}
@Override
- public void revokeRuntimePermission(String packageName, String permName,
- String persistentDeviceId, int userId, String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, String deviceId,
+ int userId, String reason) {
Log.i(LOG_TAG, "revokeRuntimePermission(packageName = " + packageName + ", permName = "
- + permName + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId
- + ", reason = " + reason + ")");
- mService.revokeRuntimePermission(packageName, permName, persistentDeviceId, userId, reason);
+ + permName + ", deviceId = " + deviceId + ", userId = " + userId + ", reason = "
+ + reason + ")");
+ mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
}
@Override
@@ -212,16 +209,16 @@
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, int userId) {
+ String deviceId, int userId) {
Log.i(LOG_TAG, "shouldShowRequestPermissionRationale(packageName = " + packageName
- + ", permName = " + permName + ", deviceId = " + deviceId
- + ", userId = " + userId + ")");
+ + ", permName = " + permName + ", deviceId = " + deviceId + ", userId = "
+ + userId + ")");
return mService.shouldShowRequestPermissionRationale(packageName, permName, deviceId,
userId);
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, String deviceId,
int userId) {
Log.i(LOG_TAG, "isPermissionRevokedByPolicy(packageName = " + packageName + ", permName = "
+ permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
@@ -235,26 +232,27 @@
}
@Override
- public int checkPermission(String pkgName, String permName, String persistentDeviceId,
+ public int checkPermission(String pkgName, String permName, String deviceId,
int userId) {
Log.i(LOG_TAG, "checkPermission(pkgName = " + pkgName + ", permName = " + permName
- + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId + ")");
- return mService.checkPermission(pkgName, permName, persistentDeviceId, userId);
+ + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+ return mService.checkPermission(pkgName, permName, deviceId, userId);
}
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
- Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = "
- + permName + ", deviceId = " + deviceId + ")");
+ public int checkUidPermission(int uid, String permName, String deviceId) {
+ Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = " + permName
+ + ", deviceId = " + deviceId + ")");
return mService.checkUidPermission(uid, permName, deviceId);
}
@Override
public Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
- @NonNull String persistentDeviceId, int userId) {
- Log.i(LOG_TAG, "getAllPermissionStates(packageName = " + packageName
- + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId + ")");
- return mService.getAllPermissionStates(packageName, persistentDeviceId, userId);
+ @NonNull String deviceId, int userId) {
+ Log.i(LOG_TAG,
+ "getAllPermissionStates(packageName = " + packageName + ", deviceId = " + deviceId
+ + ", userId = " + userId + ")");
+ return mService.getAllPermissionStates(packageName, deviceId, userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
index 0a4ff07..40139ba 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
@@ -154,12 +154,10 @@
}
@Override
- public int getPermissionFlags(String packageName, String permName, String persistentDeviceId,
+ public int getPermissionFlags(String packageName, String permName, String deviceId,
@UserIdInt int userId) {
- int oldVal = mOldImplementation.getPermissionFlags(packageName, permName,
- persistentDeviceId, userId);
- int newVal = mNewImplementation.getPermissionFlags(packageName, permName,
- persistentDeviceId, userId);
+ int oldVal = mOldImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
+ int newVal = mNewImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("getPermissionFlags");
@@ -169,12 +167,12 @@
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, String persistentDeviceId,
+ int flagValues, boolean checkAdjustPolicyFlagPermission, String deviceId,
@UserIdInt int userId) {
mOldImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, persistentDeviceId, userId);
+ checkAdjustPolicyFlagPermission, deviceId, userId);
mNewImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, persistentDeviceId, userId);
+ checkAdjustPolicyFlagPermission, deviceId, userId);
}
@Override
@@ -239,21 +237,17 @@
}
@Override
- public void grantRuntimePermission(String packageName, String permName,
- String persistentDeviceId, @UserIdInt int userId) {
- mOldImplementation.grantRuntimePermission(packageName, permName, persistentDeviceId,
- userId);
- mNewImplementation.grantRuntimePermission(packageName, permName, persistentDeviceId,
- userId);
+ public void grantRuntimePermission(String packageName, String permName, String deviceId,
+ @UserIdInt int userId) {
+ mOldImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
+ mNewImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
}
@Override
- public void revokeRuntimePermission(String packageName, String permName,
- String persistentDeviceId, @UserIdInt int userId, String reason) {
- mOldImplementation.revokeRuntimePermission(packageName, permName, persistentDeviceId,
- userId, reason);
- mNewImplementation.revokeRuntimePermission(packageName, permName, persistentDeviceId,
- userId, reason);
+ public void revokeRuntimePermission(String packageName, String permName, String deviceId,
+ @UserIdInt int userId, String reason) {
+ mOldImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+ mNewImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
}
@Override
@@ -265,7 +259,7 @@
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, @UserIdInt int userId) {
+ String deviceId, @UserIdInt int userId) {
boolean oldVal = mOldImplementation.shouldShowRequestPermissionRationale(packageName,
permName, deviceId, userId);
boolean newVal = mNewImplementation.shouldShowRequestPermissionRationale(packageName,
@@ -278,7 +272,7 @@
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, String deviceId,
@UserIdInt int userId) {
boolean oldVal = mOldImplementation.isPermissionRevokedByPolicy(packageName, permName,
deviceId, userId);
@@ -303,12 +297,9 @@
}
@Override
- public int checkPermission(String pkgName, String permName, String persistentDeviceId,
- int userId) {
- int oldVal = mOldImplementation.checkPermission(pkgName, permName, persistentDeviceId,
- userId);
- int newVal = mNewImplementation.checkPermission(pkgName, permName, persistentDeviceId,
- userId);
+ public int checkPermission(String pkgName, String permName, String deviceId, int userId) {
+ int oldVal = mOldImplementation.checkPermission(pkgName, permName, deviceId, userId);
+ int newVal = mNewImplementation.checkPermission(pkgName, permName, deviceId, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("checkPermission");
@@ -317,7 +308,7 @@
}
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
+ public int checkUidPermission(int uid, String permName, String deviceId) {
int oldVal = mOldImplementation.checkUidPermission(uid, permName, deviceId);
int newVal = mNewImplementation.checkUidPermission(uid, permName, deviceId);
@@ -329,8 +320,8 @@
@Override
public Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
- @NonNull String persistentDeviceId, int userId) {
- return mNewImplementation.getAllPermissionStates(packageName, persistentDeviceId, userId);
+ @NonNull String deviceId, int userId) {
+ return mNewImplementation.getAllPermissionStates(packageName, deviceId, userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
index bc29e67..981d3d9 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
@@ -159,11 +159,11 @@
}
@Override
- public int getPermissionFlags(String packageName, String permName, String persistentDeviceId,
+ public int getPermissionFlags(String packageName, String permName, String deviceId,
int userId) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#getPermissionFlags");
try {
- return mService.getPermissionFlags(packageName, permName, persistentDeviceId, userId);
+ return mService.getPermissionFlags(packageName, permName, deviceId, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -171,13 +171,12 @@
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, String persistentDeviceId,
- int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, String deviceId, int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#updatePermissionFlags");
try {
mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, persistentDeviceId, userId);
+ checkAdjustPolicyFlagPermission, deviceId, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -256,25 +255,24 @@
}
@Override
- public void grantRuntimePermission(String packageName, String permName,
- String persistentDeviceId, int userId) {
+ public void grantRuntimePermission(String packageName, String permName, String deviceId,
+ int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#grantRuntimePermission");
try {
- mService.grantRuntimePermission(packageName, permName, persistentDeviceId, userId);
+ mService.grantRuntimePermission(packageName, permName, deviceId, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public void revokeRuntimePermission(String packageName, String permName,
- String persistentDeviceId, int userId, String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, String deviceId,
+ int userId, String reason) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#revokeRuntimePermission");
try {
- mService.revokeRuntimePermission(packageName, permName, persistentDeviceId, userId,
- reason);
+ mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -293,19 +291,19 @@
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, int userId) {
+ String deviceId, int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#shouldShowRequestPermissionRationale");
try {
- return mService.shouldShowRequestPermissionRationale(
- packageName, permName, deviceId, userId);
+ return mService.shouldShowRequestPermissionRationale(packageName, permName, deviceId,
+ userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, String deviceId,
int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#isPermissionRevokedByPolicy");
@@ -328,18 +326,17 @@
}
@Override
- public int checkPermission(String pkgName, String permName, String persistentDeviceId,
- int userId) {
+ public int checkPermission(String pkgName, String permName, String deviceId, int userId) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkPermission");
try {
- return mService.checkPermission(pkgName, permName, persistentDeviceId, userId);
+ return mService.checkPermission(pkgName, permName, deviceId, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
+ public int checkUidPermission(int uid, String permName, String deviceId) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkUidPermission");
try {
return mService.checkUidPermission(uid, permName, deviceId);
@@ -350,11 +347,11 @@
@Override
public Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
- @NonNull String persistentDeviceId, int userId) {
+ @NonNull String deviceId, int userId) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl"
+ "#getAllPermissionStates");
try {
- return mService.getAllPermissionStates(packageName, persistentDeviceId, userId);
+ return mService.getAllPermissionStates(packageName, deviceId, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
diff --git a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
index 76952b3..1b220a0 100644
--- a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
+++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
@@ -17,7 +17,7 @@
package com.android.server.policy;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
+import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE_IDENTIFIER;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -94,7 +94,7 @@
private static final BooleanSupplier FALSE_BOOLEAN_SUPPLIER = () -> false;
@VisibleForTesting
- static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(MINIMUM_DEVICE_STATE,
+ static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(MINIMUM_DEVICE_STATE_IDENTIFIER,
"DEFAULT", 0 /* flags */);
private static final String VENDOR_CONFIG_FILE_PATH = "etc/devicestate/";
diff --git a/services/core/java/com/android/server/utils/EventLogger.java b/services/core/java/com/android/server/utils/EventLogger.java
index 4772bbf..2e1049b 100644
--- a/services/core/java/com/android/server/utils/EventLogger.java
+++ b/services/core/java/com/android/server/utils/EventLogger.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Log;
+import android.util.Slog;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -84,6 +85,17 @@
enqueue(event.printLog(logType, tag));
}
+ /**
+ * Add a string-based event to the system log, and print it to the log with a specific severity.
+ * @param msg the message to appear in the log
+ * @param logType the log severity (verbose/info/warning/error)
+ * @param tag the tag under which the log entry will appear
+ */
+ public synchronized void enqueueAndSlog(String msg, @Event.LogType int logType, String tag) {
+ final Event event = new StringEvent(msg);
+ enqueue(event.printSlog(logType, tag));
+ }
+
/** Dumps events into the given {@link DumpSink}. */
public synchronized void dump(DumpSink dumpSink) {
dumpSink.sink(mTag, new ArrayList<>(mEvents));
@@ -138,7 +150,7 @@
/**
* Causes the string message for the event to appear in the logcat.
* Here is an example of how to create a new event (a StringEvent), adding it to the logger
- * (an instance of AudioEventLogger) while also making it show in the logcat:
+ * (an instance of EventLogger) while also making it show in the logcat:
* <pre>
* myLogger.log(
* (new StringEvent("something for logcat and logger")).printLog(MyClass.TAG) );
@@ -167,9 +179,9 @@
/**
* Same as {@link #printLog(String)} with a log type
- * @param type one of {@link #ALOGI}, {@link #ALOGE}, {@link #ALOGV}
- * @param tag
- * @return
+ * @param type one of {@link #ALOGI}, {@link #ALOGE}, {@link #ALOGV}, {@link #ALOGW}
+ * @param tag the tag the log entry will be printed under
+ * @return the event itself
*/
public Event printLog(@LogType int type, String tag) {
switch (type) {
@@ -191,6 +203,32 @@
}
/**
+ * Causes the string message for the event to appear in the system log.
+ * @param type one of {@link #ALOGI}, {@link #ALOGE}, {@link #ALOGV}, {@link #ALOGW}
+ * @param tag the tag the log entry will be printed under
+ * @return the event itself
+ * @see #printLog(int, String)
+ */
+ public Event printSlog(@LogType int type, String tag) {
+ switch (type) {
+ case ALOGI:
+ Slog.i(tag, eventToString());
+ break;
+ case ALOGE:
+ Slog.e(tag, eventToString());
+ break;
+ case ALOGW:
+ Slog.w(tag, eventToString());
+ break;
+ case ALOGV:
+ default:
+ Slog.v(tag, eventToString());
+ break;
+ }
+ return this;
+ }
+
+ /**
* Convert event to String.
* This method is only called when the logger history is about to the dumped,
* so this method is where expensive String conversions should be made, not when the Event
diff --git a/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
index db27f60..01d077a 100644
--- a/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
+++ b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
@@ -22,12 +22,10 @@
import android.annotation.NonNull;
import android.app.compat.CompatChanges;
-import android.content.pm.PackageManager;
import android.provider.DeviceConfig;
import com.android.internal.annotations.GuardedBy;
-import java.util.HashSet;
import java.util.concurrent.Executor;
/**
@@ -50,74 +48,49 @@
private static final String KEY_ASM_RESTRICTIONS_ENABLED = KEY_ASM_PREFIX
+ "asm_restrictions_enabled";
private static final String KEY_ASM_TOASTS_ENABLED = KEY_ASM_PREFIX + "asm_toasts_enabled";
- private static final String KEY_ASM_EXEMPTED_PACKAGES = KEY_ASM_PREFIX
- + "asm_exempted_packages";
+
private static final int VALUE_DISABLE = 0;
private static final int VALUE_ENABLE_FOR_V = 1;
private static final int VALUE_ENABLE_FOR_ALL = 2;
private static final int DEFAULT_VALUE = VALUE_DISABLE;
- private static final String DEFAULT_EXCEPTION_LIST = "";
private static int sAsmToastsEnabled;
private static int sAsmRestrictionsEnabled;
- private static final HashSet<String> sExcludedPackageNames = new HashSet<>();
- private static PackageManager sPm;
@GuardedBy("ActivityTaskManagerService.mGlobalLock")
- static void initialize(@NonNull Executor executor, @NonNull PackageManager pm) {
+ static void initialize(@NonNull Executor executor) {
updateFromDeviceConfig();
DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, executor,
properties -> updateFromDeviceConfig());
- sPm = pm;
}
@GuardedBy("ActivityTaskManagerService.mGlobalLock")
static boolean shouldShowToast(int uid) {
- return flagEnabledForUid(sAsmToastsEnabled, uid);
+ return sAsmToastsEnabled == VALUE_ENABLE_FOR_ALL
+ || (sAsmToastsEnabled == VALUE_ENABLE_FOR_V
+ && CompatChanges.isChangeEnabled(ASM_RESTRICTIONS, uid));
}
@GuardedBy("ActivityTaskManagerService.mGlobalLock")
static boolean shouldRestrictActivitySwitch(int uid) {
- return flagEnabledForUid(sAsmRestrictionsEnabled, uid);
- }
-
- private static boolean flagEnabledForUid(int flag, int uid) {
- boolean flagEnabled = flag == VALUE_ENABLE_FOR_ALL
- || (flag == VALUE_ENABLE_FOR_V
- && CompatChanges.isChangeEnabled(ASM_RESTRICTIONS, uid));
-
- if (flagEnabled) {
- String[] packageNames = sPm.getPackagesForUid(uid);
- if (packageNames == null) {
- return true;
- }
- for (int i = 0; i < packageNames.length; i++) {
- if (sExcludedPackageNames.contains(packageNames[i])) {
- return false;
- }
- }
- return true;
+ if (android.security.Flags.asmRestrictionsEnabled()) {
+ return CompatChanges.isChangeEnabled(ASM_RESTRICTIONS, uid)
+ || asmRestrictionsEnabledForAll();
}
return false;
}
+ @GuardedBy("ActivityTaskManagerService.mGlobalLock")
+ static boolean asmRestrictionsEnabledForAll() {
+ return sAsmRestrictionsEnabled == VALUE_ENABLE_FOR_ALL;
+ }
+
private static void updateFromDeviceConfig() {
sAsmToastsEnabled = DeviceConfig.getInt(NAMESPACE, KEY_ASM_TOASTS_ENABLED,
DEFAULT_VALUE);
sAsmRestrictionsEnabled = DeviceConfig.getInt(NAMESPACE, KEY_ASM_RESTRICTIONS_ENABLED,
DEFAULT_VALUE);
-
- String rawExceptionList = DeviceConfig.getString(NAMESPACE,
- KEY_ASM_EXEMPTED_PACKAGES, DEFAULT_EXCEPTION_LIST);
- sExcludedPackageNames.clear();
- String[] packages = rawExceptionList.split(",");
- for (String packageName : packages) {
- String packageNameTrimmed = packageName.trim();
- if (!packageNameTrimmed.isEmpty()) {
- sExcludedPackageNames.add(packageNameTrimmed);
- }
- }
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0e6c06d..445295a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -881,7 +881,7 @@
mTaskSupervisor.onSystemReady();
mActivityClientController.onSystemReady();
// TODO(b/258792202) Cleanup once ASM is ready to launch
- ActivitySecurityModelFeatureFlags.initialize(mContext.getMainExecutor(), pm);
+ ActivitySecurityModelFeatureFlags.initialize(mContext.getMainExecutor());
mGrammaticalManagerInternal = LocalServices.getService(
GrammaticalInflectionManagerInternal.class);
}
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 2d6f03a..3bc5319 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -56,6 +56,7 @@
import android.compat.annotation.EnabledAfter;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Process;
import android.os.SystemClock;
@@ -529,6 +530,9 @@
static final BalVerdict BLOCK = new BalVerdict(BAL_BLOCK, false, "Blocked");
static final BalVerdict ALLOW_BY_DEFAULT =
new BalVerdict(BAL_ALLOW_DEFAULT, false, "Default");
+ // Careful using this - it will bypass all ASM checks.
+ static final BalVerdict ALLOW_PRIVILEGED =
+ new BalVerdict(BAL_ALLOW_ALLOWLISTED_UID, false, "PRIVILEGED");
private final @BalCode int mCode;
private final boolean mBackground;
private final String mMessage;
@@ -1234,7 +1238,8 @@
boolean shouldBlockActivityStart = ActivitySecurityModelFeatureFlags
.shouldRestrictActivitySwitch(callingUid);
int[] finishCount = new int[0];
- if (shouldBlockActivityStart) {
+ if (shouldBlockActivityStart
+ && blockCrossUidActivitySwitchFromBelowForActivity(targetTaskTop)) {
ActivityRecord activity = targetTask.getActivity(isLaunchingOrLaunched);
if (activity == null) {
// mStartActivity is not in task, so clear everything
@@ -1319,7 +1324,7 @@
boolean restrictActivitySwitch = ActivitySecurityModelFeatureFlags
.shouldRestrictActivitySwitch(callingUid)
- && bas.mBlockActivityStartIfFlagEnabled;
+ && bas.mBlockActivityStartIfFlagEnabled;
PackageManager pm = mService.mContext.getPackageManager();
String callingPackage = pm.getNameForUid(callingUid);
@@ -1373,19 +1378,19 @@
int uid, @Nullable ActivityRecord sourceRecord) {
// If the source is visible, consider it 'top'.
if (sourceRecord != null && sourceRecord.isVisibleRequested()) {
- return new BlockActivityStart(false, false);
+ return BlockActivityStart.ACTIVITY_START_ALLOWED;
}
// Always allow actual top activity to clear task
ActivityRecord topActivity = task.getTopMostActivity();
if (topActivity != null && topActivity.isUid(uid)) {
- return new BlockActivityStart(false, false);
+ return BlockActivityStart.ACTIVITY_START_ALLOWED;
}
// If UID is visible in target task, allow launch
if (task.forAllActivities((Predicate<ActivityRecord>)
ar -> ar.isUid(uid) && ar.isVisibleRequested())) {
- return new BlockActivityStart(false, false);
+ return BlockActivityStart.ACTIVITY_START_ALLOWED;
}
// Consider the source activity, whether or not it is finishing. Do not consider any other
@@ -1452,12 +1457,11 @@
private BlockActivityStart blockCrossUidActivitySwitchFromBelow(ActivityRecord ar,
int sourceUid) {
if (ar.isUid(sourceUid)) {
- return new BlockActivityStart(false, false);
+ return BlockActivityStart.ACTIVITY_START_ALLOWED;
}
- // If mAllowCrossUidActivitySwitchFromBelow is set, honor it.
- if (ar.mAllowCrossUidActivitySwitchFromBelow) {
- return new BlockActivityStart(false, false);
+ if (!blockCrossUidActivitySwitchFromBelowForActivity(ar)) {
+ return BlockActivityStart.ACTIVITY_START_ALLOWED;
}
// At this point, we would block if the feature is launched and both apps were V+
@@ -1468,8 +1472,11 @@
ActivitySecurityModelFeatureFlags.shouldRestrictActivitySwitch(ar.getUid())
&& ActivitySecurityModelFeatureFlags
.shouldRestrictActivitySwitch(sourceUid);
- return new BackgroundActivityStartController
- .BlockActivityStart(restrictActivitySwitch, true);
+ if (restrictActivitySwitch) {
+ return BlockActivityStart.BLOCK;
+ } else {
+ return BlockActivityStart.LOG_ONLY;
+ }
}
/**
@@ -1675,14 +1682,52 @@
}
}
- static class BlockActivityStart {
+ /**
+ * Activity level allowCrossUidActivitySwitchFromBelow defaults to false.
+ * Package level defaults to true.
+ * We block the launch if dev has explicitly set package level to false, and activity level has
+ * not opted out
+ */
+ private boolean blockCrossUidActivitySwitchFromBelowForActivity(@NonNull ActivityRecord ar) {
+ // We don't need to check package level if activity has opted out.
+ if (ar.mAllowCrossUidActivitySwitchFromBelow) {
+ return false;
+ }
+
+ if (ActivitySecurityModelFeatureFlags.asmRestrictionsEnabledForAll()) {
+ return true;
+ }
+
+ String packageName = ar.packageName;
+ if (packageName == null) {
+ return false;
+ }
+
+ PackageManager pm = mService.mContext.getPackageManager();
+ ApplicationInfo applicationInfo;
+
+ try {
+ applicationInfo = pm.getApplicationInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.wtf(TAG, "Package name: " + packageName + " not found.");
+ return false;
+ }
+
+ return !applicationInfo.allowCrossUidActivitySwitchFromBelow;
+ }
+
+ private static class BlockActivityStart {
+ private static final BlockActivityStart ACTIVITY_START_ALLOWED =
+ new BlockActivityStart(false, false);
+ private static final BlockActivityStart LOG_ONLY = new BlockActivityStart(false, true);
+ private static final BlockActivityStart BLOCK = new BlockActivityStart(true, true);
// We should block if feature flag is enabled
private final boolean mBlockActivityStartIfFlagEnabled;
// Used for logging/toasts. Would we block if target sdk was V and feature was
// enabled?
private final boolean mWouldBlockActivityStartIgnoringFlag;
- BlockActivityStart(boolean shouldBlockActivityStart,
+ private BlockActivityStart(boolean shouldBlockActivityStart,
boolean wouldBlockActivityStartIgnoringFlags) {
this.mBlockActivityStartIfFlagEnabled = shouldBlockActivityStart;
this.mWouldBlockActivityStartIgnoringFlag = wouldBlockActivityStartIgnoringFlags;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 25a5fca..e743172 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6783,14 +6783,6 @@
return mSandboxDisplayApis;
}
- /**
- * For testing only; inject a ContentRecorder instance.
- */
- @VisibleForTesting
- void setContentRecorder(ContentRecorder contentRecorder) {
- mContentRecorder = contentRecorder;
- }
-
private ContentRecorder getContentRecorder() {
if (mContentRecorder == null) {
mContentRecorder = new ContentRecorder(this);
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index e6ef90b..68bff43 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_EMBEDDED_WINDOWS;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -34,6 +35,9 @@
import android.view.InputChannel;
import android.window.InputTransferToken;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.server.input.InputManagerService;
+
/**
* Keeps track of embedded windows.
*
@@ -52,9 +56,13 @@
private final Object mGlobalLock;
private final ActivityTaskManagerService mAtmService;
- EmbeddedWindowController(ActivityTaskManagerService atmService) {
+ private final InputManagerService mInputManagerService;
+
+ EmbeddedWindowController(ActivityTaskManagerService atmService,
+ InputManagerService inputManagerService) {
mAtmService = atmService;
mGlobalLock = atmService.getGlobalLock();
+ mInputManagerService = inputManagerService;
}
/**
@@ -135,6 +143,60 @@
return mWindowsByWindowToken.get(windowToken);
}
+ private boolean isValidTouchGestureParams(WindowState hostWindowState,
+ EmbeddedWindow embeddedWindow) {
+ if (embeddedWindow == null) {
+ ProtoLog.w(WM_DEBUG_EMBEDDED_WINDOWS,
+ "Attempt to transfer touch gesture with non-existent embedded window");
+ return false;
+ }
+ final WindowState wsAssociatedWithEmbedded = embeddedWindow.getWindowState();
+ if (wsAssociatedWithEmbedded == null) {
+ ProtoLog.w(WM_DEBUG_EMBEDDED_WINDOWS,
+ "Attempt to transfer touch gesture using embedded window with no associated "
+ + "host");
+ return false;
+ }
+ if (wsAssociatedWithEmbedded.mClient.asBinder() != hostWindowState.mClient.asBinder()) {
+ ProtoLog.w(WM_DEBUG_EMBEDDED_WINDOWS,
+ "Attempt to transfer touch gesture with host window not associated with "
+ + "embedded window");
+ return false;
+ }
+
+ if (embeddedWindow.getInputChannelToken() == null) {
+ ProtoLog.w(WM_DEBUG_EMBEDDED_WINDOWS,
+ "Attempt to transfer touch gesture using embedded window that has no input "
+ + "channel");
+ return false;
+ }
+ if (hostWindowState.mInputChannelToken == null) {
+ ProtoLog.w(WM_DEBUG_EMBEDDED_WINDOWS,
+ "Attempt to transfer touch gesture using a host window with no input channel");
+ return false;
+ }
+ return true;
+ }
+
+ boolean transferToHost(InputTransferToken embeddedWindowToken,
+ WindowState transferToHostWindowState) {
+ EmbeddedWindow ew = getByInputTransferToken(embeddedWindowToken);
+ if (!isValidTouchGestureParams(transferToHostWindowState, ew)) {
+ return false;
+ }
+ return mInputManagerService.transferTouchFocus(ew.getInputChannelToken(),
+ transferToHostWindowState.mInputChannelToken);
+ }
+
+ boolean transferToEmbedded(WindowState hostWindowState, InputTransferToken transferToToken) {
+ final EmbeddedWindowController.EmbeddedWindow ew = getByInputTransferToken(transferToToken);
+ if (!isValidTouchGestureParams(hostWindowState, ew)) {
+ return false;
+ }
+ return mInputManagerService.transferTouchFocus(hostWindowState.mInputChannelToken,
+ ew.getInputChannelToken());
+ }
+
static class EmbeddedWindow implements InputTarget {
final IBinder mClient;
@Nullable final WindowState mHostWindowState;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 609ad1e..bf45804 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -612,10 +612,8 @@
}
void refreshSecureSurfaceState() {
- forAllWindows((w) -> {
- if (w.mHasSurface) {
- w.setSecureLocked(w.isSecureLocked());
- }
+ forAllWindows(w -> {
+ w.setSecureLocked(w.isSecureLocked());
}, true /* traverseTopToBottom */);
}
diff --git a/services/core/java/com/android/server/wm/SensitiveContentPackages.java b/services/core/java/com/android/server/wm/SensitiveContentPackages.java
index a7d6903b..5fe48d1 100644
--- a/services/core/java/com/android/server/wm/SensitiveContentPackages.java
+++ b/services/core/java/com/android/server/wm/SensitiveContentPackages.java
@@ -56,6 +56,17 @@
}
/**
+ * Clears apps added to collection of apps in which screen capture should be disabled.
+ *
+ * @param packageInfos set of {@link PackageInfo} whose windows should be unblocked
+ * from capture.
+ * @return {@code true} if packages set is modified, {@code false} otherwise.
+ */
+ public boolean removeBlockScreenCaptureForApps(@NonNull ArraySet<PackageInfo> packageInfos) {
+ return mProtectedPackages.removeAll(packageInfos);
+ }
+
+ /**
* Clears the set of package/uid pairs that should be blocked from screen capture
*
* @return {@code true} if packages set is modified, {@code false} otherwise.
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 3c8c55e..975208f 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -970,40 +970,6 @@
}
@Override
- public boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow) {
- if (embeddedWindow == null) {
- return false;
- }
-
- final long identity = Binder.clearCallingIdentity();
- boolean didTransfer = false;
- try {
- didTransfer = mService.transferEmbeddedTouchFocusToHost(embeddedWindow);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- return didTransfer;
- }
-
- @Override
- public boolean transferHostTouchGestureToEmbedded(IWindow hostWindow,
- InputTransferToken inputTransferToken) {
- if (hostWindow == null) {
- return false;
- }
-
- final long identity = Binder.clearCallingIdentity();
- boolean didTransfer;
- try {
- didTransfer = mService.transferHostTouchGestureToEmbedded(this, hostWindow,
- inputTransferToken);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- return didTransfer;
- }
-
- @Override
public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) {
final long identity = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index ae4c3b9..669c61c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -1043,6 +1043,15 @@
/**
* Clears apps added to collection of apps in which screen capture should be disabled.
*
+ * @param packageInfos set of {@link PackageInfo} whose windows should be unblocked
+ * from capture.
+ */
+ public abstract void removeBlockScreenCaptureForApps(
+ @NonNull ArraySet<PackageInfo> packageInfos);
+
+ /**
+ * Clears all apps added to collection of apps in which screen capture should be disabled.
+ *
* <p> This clears and resets any existing set or added applications from
* * {@link #addBlockScreenCaptureForApps(ArraySet)}
*/
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 631ebcd..3d6bd4f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -101,6 +101,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_EMBEDDED_WINDOWS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
@@ -1344,7 +1345,7 @@
LocalServices.addService(WindowManagerInternal.class, new LocalService());
LocalServices.addService(
ImeTargetVisibilityPolicy.class, new ImeTargetVisibilityPolicyImpl());
- mEmbeddedWindowController = new EmbeddedWindowController(mAtmService);
+ mEmbeddedWindowController = new EmbeddedWindowController(mAtmService, inputManager);
mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
mContext.getResources());
@@ -8632,6 +8633,17 @@
}
@Override
+ public void removeBlockScreenCaptureForApps(ArraySet<PackageInfo> packageInfos) {
+ synchronized (mGlobalLock) {
+ boolean modified =
+ mSensitiveContentPackages.removeBlockScreenCaptureForApps(packageInfos);
+ if (modified) {
+ WindowManagerService.this.refreshScreenCaptureDisabled();
+ }
+ }
+ }
+
+ @Override
public void clearBlockedApps() {
synchronized (mGlobalLock) {
boolean modified = mSensitiveContentPackages.clearBlockedApps();
@@ -9044,73 +9056,37 @@
null /* region */, clientToken);
}
- boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow) {
- final IBinder windowBinder = embeddedWindow.asBinder();
- final IBinder hostInputChannel, embeddedInputChannel;
- synchronized (mGlobalLock) {
- final EmbeddedWindowController.EmbeddedWindow ew =
- mEmbeddedWindowController.getByWindowToken(windowBinder);
- if (ew == null) {
- Slog.w(TAG, "Attempt to transfer touch focus from non-existent embedded window");
- return false;
- }
- final WindowState hostWindowState = ew.getWindowState();
- if (hostWindowState == null) {
- Slog.w(TAG, "Attempt to transfer touch focus from embedded window with no" +
- " associated host");
- return false;
- }
- embeddedInputChannel = ew.getInputChannelToken();
- if (embeddedInputChannel == null) {
- Slog.w(TAG, "Attempt to transfer touch focus from embedded window with no input" +
- " channel");
- return false;
- }
- hostInputChannel = hostWindowState.mInputChannelToken;
- if (hostInputChannel == null) {
- Slog.w(TAG, "Attempt to transfer touch focus to a host window with no" +
- " input channel");
- return false;
- }
- return mInputManager.transferTouchFocus(embeddedInputChannel, hostInputChannel);
+ @Override
+ public boolean transferTouchGesture(InputTransferToken transferFromToken,
+ InputTransferToken transferToToken) {
+ if (transferFromToken == null || transferToToken == null) {
+ ProtoLog.e(WM_DEBUG_EMBEDDED_WINDOWS,
+ "transferTouchGesture failed because args transferFromToken or "
+ + "transferToToken is null");
+ return false;
}
- }
- boolean transferHostTouchGestureToEmbedded(Session session, IWindow hostWindow,
- InputTransferToken inputTransferToken) {
- final IBinder hostInputChannel, embeddedInputChannel;
- synchronized (mGlobalLock) {
- final WindowState hostWindowState = windowForClientLocked(session, hostWindow, false);
- if (hostWindowState == null) {
- Slog.w(TAG, "Attempt to transfer touch gesture with invalid host window");
- return false;
+ final long identity = Binder.clearCallingIdentity();
+ boolean didTransfer;
+ try {
+ synchronized (mGlobalLock) {
+ // If the transferToToken exists in the input to window map, it means the request
+ // is to transfer from embedded to host. Otherwise, the transferToToken
+ // represents an embedded window so transfer from host to embedded.
+ WindowState windowStateTo = mInputToWindowMap.get(transferToToken.mToken);
+ if (windowStateTo != null) {
+ didTransfer = mEmbeddedWindowController.transferToHost(transferFromToken,
+ windowStateTo);
+ } else {
+ WindowState windowStateFrom = mInputToWindowMap.get(transferFromToken.mToken);
+ didTransfer = mEmbeddedWindowController.transferToEmbedded(windowStateFrom,
+ transferToToken);
+ }
}
-
- final EmbeddedWindowController.EmbeddedWindow ew =
- mEmbeddedWindowController.getByInputTransferToken(inputTransferToken);
- if (ew == null || ew.mHostWindowState == null) {
- Slog.w(TAG, "Attempt to transfer touch gesture to non-existent embedded window");
- return false;
- }
- if (ew.mHostWindowState.mClient.asBinder() != hostWindow.asBinder()) {
- Slog.w(TAG, "Attempt to transfer touch gesture to embedded window not associated"
- + " with host window");
- return false;
- }
- embeddedInputChannel = ew.getInputChannelToken();
- if (embeddedInputChannel == null) {
- Slog.w(TAG, "Attempt to transfer touch focus from embedded window with no input"
- + " channel");
- return false;
- }
- hostInputChannel = hostWindowState.mInputChannelToken;
- if (hostInputChannel == null) {
- Slog.w(TAG,
- "Attempt to transfer touch focus to a host window with no input channel");
- return false;
- }
- return mInputManager.transferTouchFocus(hostInputChannel, embeddedInputChannel);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
+ return didTransfer;
}
private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e619440..9b84f39 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -29,9 +29,11 @@
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AUTOFILL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_BLUETOOTH;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CALLS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION;
@@ -50,6 +52,7 @@
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_TASK;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MICROPHONE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MTE;
@@ -74,6 +77,7 @@
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_THEFT_DETECTION;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_TIME;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING;
@@ -21984,6 +21988,20 @@
}
@Override
+ public boolean isTheftDetectionTriggered(String callerPackageName) {
+ final CallerIdentity caller = getCallerIdentity(callerPackageName);
+ if (!android.app.admin.flags.Flags.deviceTheftImplEnabled()) {
+ return false;
+ }
+ enforcePermission(MANAGE_DEVICE_POLICY_THEFT_DETECTION, caller.getPackageName(),
+ caller.getUserId());
+
+ //STOPSHIP: replace 1<<9 with
+ // LockPatternUtils.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST once ag/26042068 lands
+ return 0 != (mLockPatternUtils.getStrongAuthForUser(caller.getUserId()) & (1 << 9));
+ }
+
+ @Override
public void setWifiSsidPolicy(String callerPackageName, WifiSsidPolicy policy) {
CallerIdentity caller;
@@ -22424,14 +22442,6 @@
});
}
- // Permission that will need to be created in V.
- private static final String MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL =
- "manage_device_policy_block_uninstall";
- private static final String MANAGE_DEVICE_POLICY_CAMERA_TOGGLE =
- "manage_device_policy_camera_toggle";
- private static final String MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE =
- "manage_device_policy_microphone_toggle";
-
// DPC types
private static final int NOT_A_DPC = -1;
private static final int DEFAULT_DEVICE_OWNER = 0;
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java b/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
index bf2619b..42e41d5 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
@@ -18,8 +18,8 @@
import static android.hardware.SensorManager.SENSOR_DELAY_FASTEST;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
+import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE_IDENTIFIER;
+import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE_IDENTIFIER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.TYPE_EXTERNAL;
@@ -478,7 +478,8 @@
}
public static DeviceStateConfiguration createConfig(
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
+ @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to =
+ MAXIMUM_DEVICE_STATE_IDENTIFIER) int identifier,
@NonNull String name,
@DeviceState.DeviceStateFlags int flags,
@NonNull Predicate<FoldableDeviceStateProvider> activeStatePredicate
@@ -488,7 +489,8 @@
}
public static DeviceStateConfiguration createConfig(
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
+ @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to =
+ MAXIMUM_DEVICE_STATE_IDENTIFIER) int identifier,
@NonNull String name,
@NonNull Predicate<FoldableDeviceStateProvider> activeStatePredicate
) {
@@ -498,7 +500,8 @@
/** Create a configuration with availability predicate **/
public static DeviceStateConfiguration createConfig(
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
+ @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to =
+ MAXIMUM_DEVICE_STATE_IDENTIFIER) int identifier,
@NonNull String name,
@DeviceState.DeviceStateFlags int flags,
@NonNull Predicate<FoldableDeviceStateProvider> activeStatePredicate,
@@ -543,7 +546,8 @@
* @return device state configuration
*/
public static DeviceStateConfiguration createTentModeClosedState(
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
+ @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to =
+ MAXIMUM_DEVICE_STATE_IDENTIFIER) int identifier,
@NonNull String name,
@DeviceState.DeviceStateFlags int flags,
int minClosedAngleDegrees,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 14e4481..ee758db 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -107,6 +107,7 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockSettingsInternal;
+import com.android.server.adaptiveauth.AdaptiveAuthService;
import com.android.server.am.ActivityManagerService;
import com.android.server.appbinding.AppBindingService;
import com.android.server.appop.AppOpMigrationHelper;
@@ -2615,6 +2616,12 @@
mSystemServiceManager.startService(AuthService.class);
t.traceEnd();
+ if (android.adaptiveauth.Flags.enableAdaptiveAuth()) {
+ t.traceBegin("StartAdaptiveAuthService");
+ mSystemServiceManager.startService(AdaptiveAuthService.class);
+ t.traceEnd();
+ }
+
if (!isWatch) {
// We don't run this on watches as there are no plans to use the data logged
// on watch devices.
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 5588276..cb3ee73 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -46,6 +46,7 @@
import com.android.server.pm.parsing.PackageInfoUtils
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageState
+import libcore.util.EmptyArray
class AppIdPermissionPolicy : SchemePolicy() {
private val persistence = AppIdPermissionPersistence()
@@ -73,40 +74,42 @@
}
override fun MutateStateScope.onInitialized() {
- newState.externalState.configPermissions.forEach { (permissionName, permissionEntry) ->
- val oldPermission = newState.systemState.permissions[permissionName]
- val newPermission =
- if (oldPermission != null) {
- if (permissionEntry.gids != null) {
- oldPermission.copy(
- gids = permissionEntry.gids,
- areGidsPerUser = permissionEntry.perUser
- )
- } else {
- return@forEach
- }
- } else {
- @Suppress("DEPRECATION")
- val permissionInfo =
- PermissionInfo().apply {
- name = permissionName
- packageName = PLATFORM_PACKAGE_NAME
- protectionLevel = PermissionInfo.PROTECTION_SIGNATURE
+ if (!Flags.newPermissionGidEnabled()) {
+ newState.externalState.configPermissions.forEach { (permissionName, permissionEntry) ->
+ val oldPermission = newState.systemState.permissions[permissionName]
+ val newPermission =
+ if (oldPermission != null) {
+ if (permissionEntry.gids != null) {
+ oldPermission.copy(
+ gids = permissionEntry.gids,
+ areGidsPerUser = permissionEntry.perUser
+ )
+ } else {
+ return@forEach
}
- if (permissionEntry.gids != null) {
- Permission(
- permissionInfo,
- false,
- Permission.TYPE_CONFIG,
- 0,
- permissionEntry.gids,
- permissionEntry.perUser
- )
} else {
- Permission(permissionInfo, false, Permission.TYPE_CONFIG, 0)
+ @Suppress("DEPRECATION")
+ val permissionInfo =
+ PermissionInfo().apply {
+ name = permissionName
+ packageName = PLATFORM_PACKAGE_NAME
+ protectionLevel = PermissionInfo.PROTECTION_SIGNATURE
+ }
+ if (permissionEntry.gids != null) {
+ Permission(
+ permissionInfo,
+ false,
+ Permission.TYPE_CONFIG,
+ 0,
+ permissionEntry.gids,
+ permissionEntry.perUser
+ )
+ } else {
+ Permission(permissionInfo, false, Permission.TYPE_CONFIG, 0)
+ }
}
- }
- newState.mutateSystemState().mutatePermissions()[permissionName] = newPermission
+ newState.mutateSystemState().mutatePermissions()[permissionName] = newPermission
+ }
}
}
@@ -459,7 +462,7 @@
)
return@forEachIndexed
}
- val newPermission =
+ var newPermission =
if (oldPermission != null && newPackageName != oldPermission.packageName) {
val oldPackageName = oldPermission.packageName
// Only allow system apps to redefine non-system permissions.
@@ -582,6 +585,24 @@
)
}
}
+ if (Flags.newPermissionGidEnabled()) {
+ var gids = EmptyArray.INT
+ var areGidsPerUser = false
+ if (!parsedPermission.isTree && packageState.isSystem) {
+ newState.externalState.configPermissions[permissionName]?.let {
+ gids = it.gids
+ areGidsPerUser = it.perUser
+ }
+ }
+ newPermission = Permission(
+ newPermissionInfo,
+ true,
+ Permission.TYPE_MANIFEST,
+ packageState.appId,
+ gids,
+ areGidsPerUser
+ )
+ }
if (parsedPermission.isTree) {
newState.mutateSystemState().mutatePermissionTrees()[permissionName] = newPermission
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 67f66de..0704c8f 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -466,7 +466,7 @@
return size
}
- override fun checkUidPermission(uid: Int, permissionName: String, deviceId: Int): Int {
+ override fun checkUidPermission(uid: Int, permissionName: String, deviceId: String): Int {
val userId = UserHandle.getUserId(uid)
if (!userManagerInternal.exists(userId)) {
return PackageManager.PERMISSION_DENIED
@@ -489,15 +489,9 @@
return PackageManager.PERMISSION_DENIED
}
- val persistentDeviceId = getPersistentDeviceId(deviceId)
- if (persistentDeviceId == null) {
- Slog.e(LOG_TAG, "Cannot find persistent device id for $deviceId.")
- return PackageManager.PERMISSION_DENIED
- }
-
val isPermissionGranted =
service.getState {
- isPermissionGranted(packageState, userId, permissionName, persistentDeviceId)
+ isPermissionGranted(packageState, userId, permissionName, deviceId)
}
return if (isPermissionGranted) {
PackageManager.PERMISSION_GRANTED
@@ -531,7 +525,7 @@
override fun checkPermission(
packageName: String,
permissionName: String,
- persistentDeviceId: String,
+ deviceId: String,
userId: Int
): Int {
if (!userManagerInternal.exists(userId)) {
@@ -545,9 +539,7 @@
?: return PackageManager.PERMISSION_DENIED
val isPermissionGranted =
- service.getState {
- isPermissionGranted(packageState, userId, permissionName, persistentDeviceId)
- }
+ service.getState { isPermissionGranted(packageState, userId, permissionName, deviceId) }
return if (isPermissionGranted) {
PackageManager.PERMISSION_GRANTED
} else {
@@ -565,21 +557,13 @@
packageState: PackageState,
userId: Int,
permissionName: String,
- persistentDeviceId: String
+ deviceId: String
): Boolean {
val appId = packageState.appId
// Note that instant apps can't have shared UIDs, so we only need to check the current
// package state.
val isInstantApp = packageState.getUserStateOrDefault(userId).isInstantApp
- if (
- isSinglePermissionGranted(
- appId,
- userId,
- isInstantApp,
- permissionName,
- persistentDeviceId
- )
- ) {
+ if (isSinglePermissionGranted(appId, userId, isInstantApp, permissionName, deviceId)) {
return true
}
@@ -591,7 +575,7 @@
userId,
isInstantApp,
fullerPermissionName,
- persistentDeviceId
+ deviceId
)
) {
return true
@@ -606,9 +590,9 @@
userId: Int,
isInstantApp: Boolean,
permissionName: String,
- persistentDeviceId: String,
+ deviceId: String,
): Boolean {
- val flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId)
+ val flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
if (!PermissionFlags.isPermissionGranted(flags)) {
return false
}
@@ -689,22 +673,16 @@
override fun grantRuntimePermission(
packageName: String,
permissionName: String,
- persistentDeviceId: String,
+ deviceId: String,
userId: Int
) {
- setRuntimePermissionGranted(
- packageName,
- userId,
- permissionName,
- persistentDeviceId,
- isGranted = true
- )
+ setRuntimePermissionGranted(packageName, userId, permissionName, deviceId, isGranted = true)
}
override fun revokeRuntimePermission(
packageName: String,
permissionName: String,
- persistentDeviceId: String,
+ deviceId: String,
userId: Int,
reason: String?
) {
@@ -712,7 +690,7 @@
packageName,
userId,
permissionName,
- persistentDeviceId,
+ deviceId,
isGranted = false,
revokeReason = reason
)
@@ -740,7 +718,7 @@
packageName: String,
userId: Int,
permissionName: String,
- persistentDeviceId: String,
+ deviceId: String,
isGranted: Boolean,
skipKillUid: Boolean = false,
revokeReason: String? = null
@@ -765,7 +743,7 @@
(if (isGranted) "" else "skipKillUid = $skipKillUid, reason = $revokeReason") +
", userId = $userId," +
" callingUid = $callingUidName ($callingUid))," +
- " persistentDeviceId = $persistentDeviceId",
+ " deviceId = $deviceId",
RuntimeException()
)
}
@@ -835,7 +813,7 @@
packageState,
userId,
permissionName,
- persistentDeviceId,
+ deviceId,
isGranted,
canManageRolePermission,
overridePolicyFixed,
@@ -923,7 +901,7 @@
packageState: PackageState,
userId: Int,
permissionName: String,
- persistentDeviceId: String,
+ deviceId: String,
isGranted: Boolean,
canManageRolePermission: Boolean,
overridePolicyFixed: Boolean,
@@ -982,8 +960,7 @@
}
val appId = packageState.appId
- val oldFlags =
- getPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId)
+ val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
if (permissionName !in androidPackage.requestedPermissions && oldFlags == 0) {
if (reportError) {
@@ -1055,7 +1032,7 @@
return
}
- setPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId, newFlags)
+ setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
if (permission.isRuntime) {
val action =
@@ -1089,7 +1066,7 @@
override fun getPermissionFlags(
packageName: String,
permissionName: String,
- persistentDeviceId: String,
+ deviceId: String,
userId: Int,
): Int {
if (!userManagerInternal.exists(userId)) {
@@ -1125,12 +1102,7 @@
}
val flags =
- getPermissionFlagsWithPolicy(
- packageState.appId,
- userId,
- permissionName,
- persistentDeviceId
- )
+ getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
return PermissionFlags.toApiFlags(flags)
}
@@ -1138,7 +1110,7 @@
override fun getAllPermissionStates(
packageName: String,
- persistentDeviceId: String,
+ deviceId: String,
userId: Int
): Map<String, PermissionState> {
if (!userManagerInternal.exists(userId)) {
@@ -1165,14 +1137,15 @@
val permissionFlagsMap =
service.getState {
- if (persistentDeviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT) {
+ if (deviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT) {
with(policy) { getAllPermissionFlags(packageState.appId, userId) }
} else {
with(devicePolicy) {
- getAllPermissionFlags(packageState.appId, persistentDeviceId, userId)
+ getAllPermissionFlags(packageState.appId, deviceId, userId)
}
}
- } ?: return emptyMap()
+ }
+ ?: return emptyMap()
val permissionStates = ArrayMap<String, PermissionState>()
permissionFlagsMap.forEachIndexed { _, permissionName, flags ->
@@ -1186,7 +1159,7 @@
override fun isPermissionRevokedByPolicy(
packageName: String,
permissionName: String,
- deviceId: Int,
+ deviceId: String,
userId: Int
): Boolean {
if (!userManagerInternal.exists(userId)) {
@@ -1207,24 +1180,13 @@
}
?: return false
- val persistentDeviceId = getPersistentDeviceId(deviceId)
- if (persistentDeviceId == null) {
- Slog.w(LOG_TAG, "Cannot find persistent device Id for $deviceId")
- return false
- }
-
service.getState {
- if (isPermissionGranted(packageState, userId, permissionName, persistentDeviceId)) {
+ if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
return false
}
val flags =
- getPermissionFlagsWithPolicy(
- packageState.appId,
- userId,
- permissionName,
- persistentDeviceId
- )
+ getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
return flags.hasBits(PermissionFlags.POLICY_FIXED)
}
@@ -1248,7 +1210,7 @@
override fun shouldShowRequestPermissionRationale(
packageName: String,
permissionName: String,
- deviceId: Int,
+ deviceId: String,
userId: Int,
): Boolean {
if (!userManagerInternal.exists(userId)) {
@@ -1274,19 +1236,13 @@
return false
}
- val persistentDeviceId = getPersistentDeviceId(deviceId)
- if (persistentDeviceId == null) {
- Slog.w(LOG_TAG, "Cannot find persistent device Id for $deviceId")
- return false
- }
-
val flags: Int
service.getState {
- if (isPermissionGranted(packageState, userId, permissionName, persistentDeviceId)) {
+ if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
return false
}
- flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId)
+ flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
}
if (flags.hasAnyBit(UNREQUESTABLE_MASK)) {
return false
@@ -1325,7 +1281,7 @@
flagMask: Int,
flagValues: Int,
enforceAdjustPolicyPermission: Boolean,
- persistentDeviceId: String,
+ deviceId: String,
userId: Int
) {
val callingUid = Binder.getCallingUid()
@@ -1351,7 +1307,7 @@
"updatePermissionFlags(packageName = $packageName," +
" permissionName = $permissionName, flagMask = $flagMaskString," +
" flagValues = $flagValuesString, userId = $userId," +
- " persistentDeviceId = $persistentDeviceId," +
+ " deviceId = $deviceId," +
" callingUid = $callingUidName ($callingUid))",
RuntimeException()
)
@@ -1441,7 +1397,7 @@
appId,
userId,
permissionName,
- persistentDeviceId,
+ deviceId,
flagMask,
flagValues,
canUpdateSystemFlags,
@@ -1527,7 +1483,7 @@
appId: Int,
userId: Int,
permissionName: String,
- persistentDeviceId: String,
+ deviceId: String,
flagMask: Int,
flagValues: Int,
canUpdateSystemFlags: Boolean,
@@ -1561,8 +1517,7 @@
return
}
- val oldFlags =
- getPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId)
+ val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
if (!isPermissionRequested && oldFlags == 0) {
Slog.w(
LOG_TAG,
@@ -1573,7 +1528,7 @@
}
val newFlags = PermissionFlags.updateFlags(permission, oldFlags, flagMask, flagValues)
- setPermissionFlagsWithPolicy(appId, userId, permissionName, persistentDeviceId, newFlags)
+ setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
}
override fun getAllowlistedRestrictedPermissions(
@@ -1648,11 +1603,11 @@
appId: Int,
userId: Int,
permissionName: String,
- persistentDeviceId: String,
+ deviceId: String,
): Int {
return if (
!Flags.deviceAwarePermissionApisEnabled() ||
- persistentDeviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
+ deviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
) {
with(policy) { getPermissionFlags(appId, userId, permissionName) }
} else {
@@ -1664,9 +1619,7 @@
)
return with(policy) { getPermissionFlags(appId, userId, permissionName) }
}
- with(devicePolicy) {
- getPermissionFlags(appId, persistentDeviceId, userId, permissionName)
- }
+ with(devicePolicy) { getPermissionFlags(appId, deviceId, userId, permissionName) }
}
}
@@ -1674,12 +1627,12 @@
appId: Int,
userId: Int,
permissionName: String,
- persistentDeviceId: String,
+ deviceId: String,
flags: Int
): Boolean {
return if (
!Flags.deviceAwarePermissionApisEnabled() ||
- persistentDeviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
+ deviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
) {
with(policy) { setPermissionFlags(appId, userId, permissionName, flags) }
} else {
@@ -1693,23 +1646,11 @@
}
with(devicePolicy) {
- setPermissionFlags(appId, persistentDeviceId, userId, permissionName, flags)
+ setPermissionFlags(appId, deviceId, userId, permissionName, flags)
}
}
}
- private fun getPersistentDeviceId(deviceId: Int): String? {
- if (deviceId == Context.DEVICE_ID_DEFAULT) {
- return VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
- }
-
- if (virtualDeviceManagerInternal == null) {
- virtualDeviceManagerInternal =
- LocalServices.getService(VirtualDeviceManagerInternal::class.java)
- }
- return virtualDeviceManagerInternal?.getPersistentIdForDevice(deviceId)
- }
-
/**
* This method does not enforce checks on the caller, should only be called after required
* checks.
@@ -2270,9 +2211,9 @@
userState.appIdDevicePermissionFlags[appId]?.forEachIndexed {
_,
- persistentDeviceId,
+ deviceId,
devicePermissionFlags ->
- println("Permissions (Device $persistentDeviceId):")
+ println("Permissions (Device $deviceId):")
withIndent {
devicePermissionFlags.forEachIndexed { _, permissionName, flags ->
val isGranted = PermissionFlags.isPermissionGranted(flags)
@@ -2415,9 +2356,8 @@
with(devicePolicy) { trimDevicePermissionStates(persistentDeviceIds) }
}
}
- virtualDeviceManagerInternal?.registerPersistentDeviceIdRemovedListener { persistentDeviceId
- ->
- service.mutateState { with(devicePolicy) { onDeviceIdRemoved(persistentDeviceId) } }
+ virtualDeviceManagerInternal?.registerPersistentDeviceIdRemovedListener { deviceId ->
+ service.mutateState { with(devicePolicy) { onDeviceIdRemoved(deviceId) } }
}
permissionControllerManager =
@@ -2764,7 +2704,7 @@
override fun onDevicePermissionFlagsChanged(
appId: Int,
userId: Int,
- persistentDeviceId: String,
+ deviceId: String,
permissionName: String,
oldFlags: Int,
newFlags: Int
@@ -2787,8 +2727,7 @@
permissionName in NOTIFICATIONS_PERMISSIONS &&
runtimePermissionRevokedUids.get(uid, true)
}
- runtimePermissionChangedUidDevices.getOrPut(uid) { mutableSetOf() } +=
- persistentDeviceId
+ runtimePermissionChangedUidDevices.getOrPut(uid) { mutableSetOf() } += deviceId
}
if (permission.hasGids && !wasPermissionGranted && isPermissionGranted) {
@@ -2803,8 +2742,8 @@
}
runtimePermissionChangedUidDevices.forEachIndexed { _, uid, persistentDeviceIds ->
- persistentDeviceIds.forEach { persistentDeviceId ->
- onPermissionsChangeListeners.onPermissionsChanged(uid, persistentDeviceId)
+ persistentDeviceIds.forEach { deviceId ->
+ onPermissionsChangeListeners.onPermissionsChanged(uid, deviceId)
}
}
runtimePermissionChangedUidDevices.clear()
@@ -2844,8 +2783,11 @@
private fun isAppBackupAndRestoreRunning(uid: Int): Boolean {
if (
- checkUidPermission(uid, Manifest.permission.BACKUP, Context.DEVICE_ID_DEFAULT) !=
- PackageManager.PERMISSION_GRANTED
+ checkUidPermission(
+ uid,
+ Manifest.permission.BACKUP,
+ VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
+ ) != PackageManager.PERMISSION_GRANTED
) {
return false
}
@@ -2879,16 +2821,16 @@
when (msg.what) {
MSG_ON_PERMISSIONS_CHANGED -> {
val uid = msg.arg1
- val persistentDeviceId = msg.obj as String
- handleOnPermissionsChanged(uid, persistentDeviceId)
+ val deviceId = msg.obj as String
+ handleOnPermissionsChanged(uid, deviceId)
}
}
}
- private fun handleOnPermissionsChanged(uid: Int, persistentDeviceId: String) {
+ private fun handleOnPermissionsChanged(uid: Int, deviceId: String) {
listeners.broadcast { listener ->
try {
- listener.onPermissionsChanged(uid, persistentDeviceId)
+ listener.onPermissionsChanged(uid, deviceId)
} catch (e: RemoteException) {
Slog.e(LOG_TAG, "Error when calling OnPermissionsChangeListener", e)
}
@@ -2903,9 +2845,9 @@
listeners.unregister(listener)
}
- fun onPermissionsChanged(uid: Int, persistentDeviceId: String) {
+ fun onPermissionsChanged(uid: Int, deviceId: String) {
if (listeners.registeredCallbackCount > 0) {
- obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0, persistentDeviceId).sendToTarget()
+ obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0, deviceId).sendToTarget()
}
}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
index bd86fe2..f15e533 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
@@ -32,8 +32,6 @@
"androidx.test.runner",
"truth",
"Harrier",
- "frameworks-base-testutils",
- "services.core",
],
platform_apis: true,
certificate: "platform",
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
index c615823..4012d8e 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
@@ -16,36 +16,32 @@
package com.android.server.pm.test.appenumeration;
+import static android.content.Context.MEDIA_PROJECTION_SERVICE;
+
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.MockitoAnnotations.initMocks;
-
-import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.PendingIntent;
import android.content.Context;
import android.content.IntentSender;
import android.content.pm.IPackageManager;
import android.content.pm.ProviderInfo;
+import android.media.projection.IMediaProjectionManager;
import android.media.projection.MediaProjectionManager;
import android.os.Process;
+import android.os.ServiceManager;
import android.os.UserHandle;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.util.test.LocalServiceKeeperRule;
-import com.android.server.media.projection.MediaProjectionManagerService;
-
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
import java.util.ArrayList;
import java.util.List;
@@ -77,17 +73,9 @@
private IPackageManager mIPackageManager;
- @Rule
- public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule();
-
- @Mock private ActivityManagerInternal mActivityManagerInternal;
-
@Before
public void setup() {
- initMocks(this);
mIPackageManager = AppGlobals.getPackageManager();
- mLocalServiceKeeperRule.overrideLocalService(ActivityManagerInternal.class,
- mActivityManagerInternal);
}
@After
@@ -181,11 +169,11 @@
public void mediaProjectionManager_createProjection_canSeeForceQueryable()
throws Exception {
installPackage(SHARED_USER_APK_PATH, true /* forceQueryable */);
- final Context context = InstrumentationRegistry.getInstrumentation().getContext();
- final MediaProjectionManagerService mediaProjectionManager =
- new MediaProjectionManagerService(context);
+ final IMediaProjectionManager mediaProjectionManager =
+ IMediaProjectionManager.Stub.asInterface(
+ ServiceManager.getService(MEDIA_PROJECTION_SERVICE));
- assertThat(mediaProjectionManager.createProjectionInternal(0 /* uid */, TARGET_SHARED_USER,
+ assertThat(mediaProjectionManager.createProjection(0 /* uid */, TARGET_SHARED_USER,
MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */))
.isNotNull();
}
@@ -193,13 +181,12 @@
@Test
public void mediaProjectionManager_createProjection_cannotSeeTarget() {
installPackage(SHARED_USER_APK_PATH, false /* forceQueryable */);
- final Context context = InstrumentationRegistry.getInstrumentation().getContext();
- final MediaProjectionManagerService mediaProjectionManager =
- new MediaProjectionManagerService(context);
+ final IMediaProjectionManager mediaProjectionManager =
+ IMediaProjectionManager.Stub.asInterface(
+ ServiceManager.getService(MEDIA_PROJECTION_SERVICE));
Assert.assertThrows(IllegalArgumentException.class,
- () -> mediaProjectionManager.createProjectionInternal(0 /* uid */,
- TARGET_SHARED_USER,
+ () -> mediaProjectionManager.createProjection(0 /* uid */, TARGET_SHARED_USER,
MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */));
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index cfe701f..d4b57f1 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -273,7 +273,8 @@
AndroidPackage::hasRequestForegroundServiceExemption,
AndroidPackage::hasRequestRawExternalStorageAccess,
AndroidPackage::isUpdatableSystem,
- AndroidPackage::getEmergencyInstaller
+ AndroidPackage::getEmergencyInstaller,
+ AndroidPackage::isAllowCrossUidActivitySwitchFromBelow,
)
override fun extraParams() = listOf(
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index d876dae..47928bc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -72,6 +72,8 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalAnswers.answer;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
@@ -157,9 +159,11 @@
private static final int MOCKAPP2_UID_OTHER = MOCKAPP2_UID + UserHandle.PER_USER_RANGE;
private static final int MOCKAPP_ISOLATED_UID = Process.FIRST_ISOLATED_UID + 321;
private static final String MOCKAPP_ISOLATED_PROCESSNAME = "isolated test #1";
+ private static final int MOCKAPP_SDK_SANDBOX_UID = Process.FIRST_SDK_SANDBOX_UID + 654;
+ private static final String MOCKAPP_SDK_SANDBOX_PROCESSNAME = "sandbox test #1";
private static int sFirstCachedAdj = ProcessList.CACHED_APP_MIN_ADJ
- + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
+ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
private static Context sContext;
private static PackageManagerInternal sPackageManagerInternal;
private static ActivityManagerService sService;
@@ -271,7 +275,6 @@
/**
* Replace the process LRU with the given processes.
- * @param apps
*/
@SuppressWarnings("GuardedBy")
private void setProcessesToLru(ProcessRecord... apps) {
@@ -660,7 +663,7 @@
app.mState.setLastTopTime(nowUptime);
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
- null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+ null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
@@ -682,7 +685,7 @@
app.mState.setLastTopTime(nowUptime);
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
- null, Context.BIND_ALMOST_PERCEPTIBLE + 2, mock(IBinder.class));
+ null, null, Context.BIND_ALMOST_PERCEPTIBLE + 2, mock(IBinder.class));
s.lastTopAlmostPerceptibleBindRequestUptimeMs =
nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
@@ -704,7 +707,7 @@
app.mState.setLastTopTime(nowUptime);
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
- null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+ null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
s.lastTopAlmostPerceptibleBindRequestUptimeMs =
nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
s.getConnections().clear();
@@ -729,7 +732,7 @@
system.mState.setHasTopUi(true);
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
- null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+ null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(system, app);
@@ -901,7 +904,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- ServiceRecord s = bindService(app, client, null, Context.BIND_WAIVE_PRIORITY,
+ ServiceRecord s = bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY,
mock(IBinder.class));
s.startRequested = true;
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -921,7 +924,7 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
client.mServices.setTreatLikeActivity(true);
- bindService(app, client, null, Context.BIND_WAIVE_PRIORITY
+ bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY
| Context.BIND_TREAT_LIKE_ACTIVITY, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
@@ -937,7 +940,7 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
IBinder binder = mock(IBinder.class);
- ServiceRecord s = bindService(app, client, null, Context.BIND_WAIVE_PRIORITY
+ ServiceRecord s = bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY
| Context.BIND_ADJUST_WITH_ACTIVITY | Context.BIND_IMPORTANT, binder);
ConnectionRecord cr = s.getConnections().get(binder).get(0);
setFieldValue(ConnectionRecord.class, cr, "activity",
@@ -955,7 +958,7 @@
public void testUpdateOomAdj_DoOne_Service_Self() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
- bindService(app, app, null, 0, mock(IBinder.class));
+ bindService(app, app, null, null, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -970,7 +973,7 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
client.mServices.setTreatLikeActivity(true);
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
@@ -988,7 +991,8 @@
doReturn(true).when(wpc).hasActivities();
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, Context.BIND_ALLOW_OOM_MANAGEMENT, mock(IBinder.class));
+ bindService(app, client, null, null, Context.BIND_ALLOW_OOM_MANAGEMENT,
+ mock(IBinder.class));
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
doReturn(client).when(sService).getTopApp();
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -1005,7 +1009,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
+ bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
client.mState.setHasTopUi(true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -1023,7 +1027,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, Context.BIND_IMPORTANT, mock(IBinder.class));
+ bindService(app, client, null, null, Context.BIND_IMPORTANT, mock(IBinder.class));
client.mServices.startExecutingService(mock(ServiceRecord.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
@@ -1039,7 +1043,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
doReturn(client).when(sService).getTopApp();
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -1056,7 +1060,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
+ bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
@@ -1074,7 +1078,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
+ bindService(app, client, null, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
@@ -1090,7 +1094,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
@@ -1109,7 +1113,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
@@ -1172,8 +1176,8 @@
ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app1, pers, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
- bindService(app2, app1, null, 0, mock(IBinder.class));
+ bindService(app1, pers, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
+ bindService(app2, app1, null, null, 0, mock(IBinder.class));
updateOomAdj(pers, app1, app2);
@@ -1192,7 +1196,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
+ bindService(app, client, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
backupTarget.app = client;
doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt());
@@ -1218,7 +1222,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
+ bindService(app, client, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
client.mState.setRunningRemoteAnimation(true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
@@ -1233,7 +1237,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, Context.BIND_NOT_VISIBLE, mock(IBinder.class));
+ bindService(app, client, null, null, Context.BIND_NOT_VISIBLE, mock(IBinder.class));
client.mState.setRunningRemoteAnimation(true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
@@ -1248,7 +1252,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
client.mState.setHasOverlayUi(true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
@@ -1264,7 +1268,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null,
+ bindService(app, client, null, null,
Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
@@ -1283,7 +1287,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
WindowProcessController wpc = client.getWindowProcessController();
doReturn(true).when(wpc).isHeavyWeightProcess();
- bindService(app, client, null,
+ bindService(app, client, null, null,
Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
@@ -1301,7 +1305,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null,
+ bindService(app, client, null, null,
Context.BIND_ALMOST_PERCEPTIBLE,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
@@ -1320,7 +1324,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
WindowProcessController wpc = client.getWindowProcessController();
doReturn(true).when(wpc).isHeavyWeightProcess();
- bindService(app, client, null,
+ bindService(app, client, null, null,
Context.BIND_ALMOST_PERCEPTIBLE,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
@@ -1341,7 +1345,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
client.mState.setRunningRemoteAnimation(true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
@@ -1356,7 +1360,8 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, Context.BIND_IMPORTANT_BACKGROUND, mock(IBinder.class));
+ bindService(app, client, null, null, Context.BIND_IMPORTANT_BACKGROUND,
+ mock(IBinder.class));
client.mState.setHasOverlayUi(true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
@@ -1496,10 +1501,10 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(client, client2, null, 0, mock(IBinder.class));
+ bindService(client, client2, null, null, 0, mock(IBinder.class));
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
doReturn(client2).when(sService).getTopApp();
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -1517,10 +1522,10 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(app, client2, null, 0, mock(IBinder.class));
+ bindService(app, client2, null, null, 0, mock(IBinder.class));
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
@@ -1537,10 +1542,10 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(client, client2, null, 0, mock(IBinder.class));
+ bindService(client, client2, null, null, 0, mock(IBinder.class));
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
@@ -1557,12 +1562,12 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(client, client2, null, 0, mock(IBinder.class));
+ bindService(client, client2, null, null, 0, mock(IBinder.class));
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- bindService(client2, app, null, 0, mock(IBinder.class));
+ bindService(client2, app, null, null, 0, mock(IBinder.class));
// Note: We add processes to LRU but still call updateOomAdjLocked() with a specific
// processes.
@@ -1599,11 +1604,11 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
- bindService(client, app, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
+ bindService(client, app, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(client2, client, null, 0, mock(IBinder.class));
+ bindService(client2, client, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
@@ -1626,11 +1631,11 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(client, client2, null, 0, mock(IBinder.class));
- bindService(client2, client, null, 0, mock(IBinder.class));
+ bindService(client, client2, null, null, 0, mock(IBinder.class));
+ bindService(client2, client, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
@@ -1653,18 +1658,18 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(client, client2, null, 0, mock(IBinder.class));
- bindService(client2, client, null, 0, mock(IBinder.class));
+ bindService(client, client2, null, null, 0, mock(IBinder.class));
+ bindService(client2, client, null, null, 0, mock(IBinder.class));
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- bindService(client3, client, null, 0, mock(IBinder.class));
+ bindService(client3, client, null, null, 0, mock(IBinder.class));
ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
- bindService(client3, client4, null, 0, mock(IBinder.class));
- bindService(client4, client3, null, 0, mock(IBinder.class));
+ bindService(client3, client4, null, null, 0, mock(IBinder.class));
+ bindService(client4, client3, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
@@ -1693,16 +1698,16 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(client, client2, null, 0, mock(IBinder.class));
+ bindService(client, client2, null, null, 0, mock(IBinder.class));
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- bindService(client2, app, null, 0, mock(IBinder.class));
+ bindService(client2, app, null, null, 0, mock(IBinder.class));
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.mState.setForcingToImportant(new Object());
- bindService(app, client3, null, 0, mock(IBinder.class));
+ bindService(app, client3, null, null, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
@@ -1718,17 +1723,17 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(client, client2, null, 0, mock(IBinder.class));
- bindService(client2, app, null, 0, mock(IBinder.class));
+ bindService(client, client2, null, null, 0, mock(IBinder.class));
+ bindService(client2, app, null, null, 0, mock(IBinder.class));
WindowProcessController wpc = client2.getWindowProcessController();
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.mState.setForcingToImportant(new Object());
- bindService(app, client3, null, 0, mock(IBinder.class));
+ bindService(app, client3, null, null, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
@@ -1743,11 +1748,11 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(client, client2, null, 0, mock(IBinder.class));
- bindService(client2, app, null, 0, mock(IBinder.class));
+ bindService(client, client2, null, null, 0, mock(IBinder.class));
+ bindService(client2, app, null, null, 0, mock(IBinder.class));
WindowProcessController wpc = client2.getWindowProcessController();
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
@@ -1755,7 +1760,7 @@
ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
client4.mState.setForcingToImportant(new Object());
- bindService(app, client4, null, 0, mock(IBinder.class));
+ bindService(app, client4, null, null, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
@@ -1770,21 +1775,21 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(client, client2, null, 0, mock(IBinder.class));
- bindService(client2, app, null, 0, mock(IBinder.class));
+ bindService(client, client2, null, null, 0, mock(IBinder.class));
+ bindService(client2, app, null, null, 0, mock(IBinder.class));
WindowProcessController wpc = client2.getWindowProcessController();
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.mState.setForcingToImportant(new Object());
- bindService(app, client3, null, 0, mock(IBinder.class));
+ bindService(app, client3, null, null, 0, mock(IBinder.class));
ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
client4.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- bindService(app, client4, null, 0, mock(IBinder.class));
+ bindService(app, client4, null, null, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
@@ -1802,15 +1807,15 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
WindowProcessController wpc = client.getWindowProcessController();
doReturn(true).when(wpc).isHomeProcess();
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(app, client2, null, 0, mock(IBinder.class));
+ bindService(app, client2, null, null, 0, mock(IBinder.class));
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.mState.setForcingToImportant(new Object());
- bindService(app, client3, null, 0, mock(IBinder.class));
+ bindService(app, client3, null, null, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, client3, app);
@@ -1826,7 +1831,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
@@ -1846,12 +1851,12 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, 0, mock(IBinder.class));
+ bindService(app, client, null, null, 0, mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- bindService(client2, app, null, 0, mock(IBinder.class));
+ bindService(client2, app, null, null, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
@@ -1912,9 +1917,9 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
final ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- bindService(app1, client1, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+ bindService(app1, client1, null, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
mock(IBinder.class));
- bindService(app2, client2, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+ bindService(app2, client2, null, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
mock(IBinder.class));
client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
@@ -1929,8 +1934,10 @@
assertBfsl(app1);
assertBfsl(app2);
- bindService(app1, client1, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class));
- bindService(app2, client2, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class));
+ bindService(app1, client1, null, null, Context.BIND_SCHEDULE_LIKE_TOP_APP,
+ mock(IBinder.class));
+ bindService(app2, client2, null, null, Context.BIND_SCHEDULE_LIKE_TOP_APP,
+ mock(IBinder.class));
updateOomAdj(client1, client2, app1, app2);
assertProcStates(app1, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -1946,8 +1953,8 @@
SCHED_GROUP_DEFAULT);
assertBfsl(app2);
- bindService(client2, app1, null, 0, mock(IBinder.class));
- bindService(app1, client2, null, 0, mock(IBinder.class));
+ bindService(client2, app1, null, null, 0, mock(IBinder.class));
+ bindService(app1, client2, null, null, 0, mock(IBinder.class));
client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
updateOomAdj(app1, client1, client2);
assertProcStates(app1, PROCESS_STATE_IMPORTANT_FOREGROUND, VISIBLE_APP_ADJ,
@@ -1968,9 +1975,9 @@
client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
client2.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- final ServiceRecord s1 = bindService(app1, client1, null,
+ final ServiceRecord s1 = bindService(app1, client1, null, null,
Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE, mock(IBinder.class));
- final ServiceRecord s2 = bindService(app2, client2, null,
+ final ServiceRecord s2 = bindService(app2, client2, null, null,
Context.BIND_IMPORTANT, mock(IBinder.class));
updateOomAdj(client1, client2, app1, app2);
@@ -1980,7 +1987,7 @@
assertProcStates(app2, PROCESS_STATE_PERSISTENT, PERSISTENT_SERVICE_ADJ,
SCHED_GROUP_DEFAULT);
- bindService(app2, client1, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
+ bindService(app2, client1, null, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
mock(IBinder.class));
updateOomAdj(app2);
assertProcStates(app2, PROCESS_STATE_PERSISTENT, PERSISTENT_SERVICE_ADJ,
@@ -1995,9 +2002,9 @@
client1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
client2.mState.setHasOverlayUi(true);
- bindService(app1, client1, s1, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
+ bindService(app1, client1, null, s1, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
mock(IBinder.class));
- bindService(app2, client2, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
+ bindService(app2, client2, null, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
mock(IBinder.class));
updateOomAdj(client1, client2, app1, app2);
@@ -2030,7 +2037,7 @@
app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- bindService(app1, client1, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
+ bindService(app1, client1, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
updateOomAdj(client1, app1);
@@ -2051,7 +2058,8 @@
app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- bindService(app1, client1, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+ bindService(app1, client1, null, null, Context.BIND_ALMOST_PERCEPTIBLE,
+ mock(IBinder.class));
updateOomAdj(client1, app1);
@@ -2121,19 +2129,19 @@
final ComponentName cn1 = ComponentName.unflattenFromString(
MOCKAPP_PACKAGENAME + "/.TestService");
- final ServiceRecord s1 = bindService(app1, client1, null, 0, mock(IBinder.class));
+ final ServiceRecord s1 = bindService(app1, client1, null, null, 0, mock(IBinder.class));
setFieldValue(ServiceRecord.class, s1, "name", cn1);
s1.startRequested = true;
final ComponentName cn2 = ComponentName.unflattenFromString(
MOCKAPP2_PACKAGENAME + "/.TestService");
- final ServiceRecord s2 = bindService(app2, client2, null, 0, mock(IBinder.class));
+ final ServiceRecord s2 = bindService(app2, client2, null, null, 0, mock(IBinder.class));
setFieldValue(ServiceRecord.class, s2, "name", cn2);
s2.startRequested = true;
final ComponentName cn3 = ComponentName.unflattenFromString(
MOCKAPP5_PACKAGENAME + "/.TestService");
- final ServiceRecord s3 = bindService(app3, client1, null, 0, mock(IBinder.class));
+ final ServiceRecord s3 = bindService(app3, client1, null, null, 0, mock(IBinder.class));
setFieldValue(ServiceRecord.class, s3, "name", cn3);
s3.startRequested = true;
@@ -2177,7 +2185,7 @@
clientUidRecord.setIdle(true);
doReturn(ActivityManager.APP_START_MODE_DELAYED).when(sService)
.getAppStartModeLOSP(anyInt(), any(String.class), anyInt(),
- anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
+ anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
doNothing().when(sService.mServices)
.scheduleServiceTimeoutLocked(any(ProcessRecord.class));
updateOomAdj(client1, client2, app1, app2, app3);
@@ -2188,7 +2196,7 @@
} finally {
doCallRealMethod().when(sService)
.getAppStartModeLOSP(anyInt(), any(String.class), anyInt(),
- anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
+ anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
sService.mServices.mServiceMap.clear();
sService.mOomAdjuster.mActiveUids.clear();
}
@@ -2223,7 +2231,7 @@
ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
app2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- bindService(app, app2, null, 0, mock(IBinder.class));
+ bindService(app, app2, null, null, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2);
@@ -2242,12 +2250,12 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, app2, null, 0, mock(IBinder.class));
+ bindService(app, app2, null, null, 0, mock(IBinder.class));
ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(app2, app3, null, 0, mock(IBinder.class));
+ bindService(app2, app3, null, null, 0, mock(IBinder.class));
app3.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- bindService(app3, app, null, 0, mock(IBinder.class));
+ bindService(app3, app, null, null, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2, app3);
@@ -2278,21 +2286,21 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+ ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(app2, app3, null, 0, mock(IBinder.class));
- bindService(app3, app, null, 0, mock(IBinder.class));
+ bindService(app2, app3, null, null, 0, mock(IBinder.class));
+ bindService(app3, app, null, null, 0, mock(IBinder.class));
WindowProcessController wpc = app3.getWindowProcessController();
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
app4.mState.setHasOverlayUi(true);
- bindService(app, app4, s, 0, mock(IBinder.class));
+ bindService(app, app4, null, s, 0, mock(IBinder.class));
ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- bindService(app, app5, s, 0, mock(IBinder.class));
+ bindService(app, app5, null, s, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2, app3, app4, app5);
@@ -2320,21 +2328,21 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+ ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(app2, app3, null, 0, mock(IBinder.class));
- bindService(app3, app, null, 0, mock(IBinder.class));
+ bindService(app2, app3, null, null, 0, mock(IBinder.class));
+ bindService(app3, app, null, null, 0, mock(IBinder.class));
WindowProcessController wpc = app3.getWindowProcessController();
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
app4.mState.setHasOverlayUi(true);
- bindService(app, app4, s, 0, mock(IBinder.class));
+ bindService(app, app4, null, s, 0, mock(IBinder.class));
ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- bindService(app, app5, s, 0, mock(IBinder.class));
+ bindService(app, app5, null, s, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app5, app4, app3, app2, app);
@@ -2362,21 +2370,21 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+ ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(app2, app3, null, 0, mock(IBinder.class));
- bindService(app3, app, null, 0, mock(IBinder.class));
+ bindService(app2, app3, null, null, 0, mock(IBinder.class));
+ bindService(app3, app, null, null, 0, mock(IBinder.class));
WindowProcessController wpc = app3.getWindowProcessController();
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
app4.mState.setHasOverlayUi(true);
- bindService(app, app4, s, 0, mock(IBinder.class));
+ bindService(app, app4, null, s, 0, mock(IBinder.class));
ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- bindService(app, app5, s, 0, mock(IBinder.class));
+ bindService(app, app5, null, s, 0, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app3, app4, app2, app, app5);
@@ -2404,15 +2412,19 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- bindService(app, client, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
+ bindService(app, client, null, null, Context.BIND_INCLUDE_CAPABILITIES,
+ mock(IBinder.class));
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- bindService(client, client2, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
- bindService(client2, app, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
+ bindService(client, client2, null, null, Context.BIND_INCLUDE_CAPABILITIES,
+ mock(IBinder.class));
+ bindService(client2, app, null, null, Context.BIND_INCLUDE_CAPABILITIES,
+ mock(IBinder.class));
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- bindService(app, client3, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
+ bindService(app, client3, null, null, Context.BIND_INCLUDE_CAPABILITIES,
+ mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
@@ -2472,10 +2484,10 @@
ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
long now = SystemClock.uptimeMillis();
- ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+ ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
s.startRequested = true;
s.lastActivity = now;
- s = bindService(app2, app, null, 0, mock(IBinder.class));
+ s = bindService(app2, app, null, null, 0, mock(IBinder.class));
s.startRequested = true;
s.lastActivity = now;
ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
@@ -2507,11 +2519,11 @@
final int userOwner = 0;
final int userOther = 1;
final int cachedAdj1 = sService.mConstants.USE_TIERED_CACHED_ADJ
- ? CACHED_APP_MIN_ADJ + 10
- : CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
+ ? CACHED_APP_MIN_ADJ + 10
+ : CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
final int cachedAdj2 = sService.mConstants.USE_TIERED_CACHED_ADJ
- ? CACHED_APP_MIN_ADJ + 10
- : cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
+ ? CACHED_APP_MIN_ADJ + 10
+ : cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
doReturn(userOwner).when(sService.mUserController).getCurrentUserId();
final ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
@@ -2626,7 +2638,7 @@
// Simulate binding to a service in the same process using BIND_ABOVE_CLIENT and
// verify that its OOM adjustment level is unaffected.
- bindService(app, app, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
+ bindService(app, app, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
app.mServices.updateHasAboveClientLocked();
assertFalse(app.mServices.hasAboveClient());
@@ -2644,12 +2656,12 @@
final ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
long now = SystemClock.uptimeMillis();
- ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+ ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
s.startRequested = true;
s.lastActivity = now;
- s = bindService(app2, app3, null, 0, mock(IBinder.class));
+ s = bindService(app2, app3, null, null, 0, mock(IBinder.class));
s.lastActivity = now;
- s = bindService(app3, app2, null, 0, mock(IBinder.class));
+ s = bindService(app3, app2, null, null, 0, mock(IBinder.class));
s.lastActivity = now;
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -2678,7 +2690,7 @@
// Start binding to a service that isn't running yet.
ServiceRecord sr = makeServiceRecord(app);
sr.app = null;
- bindService(null, app, sr, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
+ bindService(null, app, null, sr, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
// Since sr.app is null, this service cannot be in the same process as the
// client so we expect the BIND_ABOVE_CLIENT adjustment to take effect.
@@ -2772,91 +2784,37 @@
ApplicationExitInfo.SUBREASON_ISOLATED_NOT_NEEDED, true);
}
- private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
- String packageName, boolean hasShownUi) {
- long now = SystemClock.uptimeMillis();
- return makeProcessRecord(sService, pid, uid, processName,
- packageName, 12345, Build.VERSION_CODES.CUR_DEVELOPMENT,
- now, now, now, 12345, UNKNOWN_ADJ, UNKNOWN_ADJ,
- UNKNOWN_ADJ, CACHED_APP_MAX_ADJ,
- SCHED_GROUP_DEFAULT, SCHED_GROUP_DEFAULT,
- PROCESS_STATE_NONEXISTENT, PROCESS_STATE_NONEXISTENT,
- PROCESS_STATE_NONEXISTENT, PROCESS_STATE_NONEXISTENT,
- 0, 0, false, false, false, ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE,
- false, false, false, hasShownUi, false, false, false, false, false, false, null,
- 0, Long.MIN_VALUE, Long.MIN_VALUE, true, 0, null, false);
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testUpdateOomAdj_DoAll_SdkSandbox_attributedClient() {
+ ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+ MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ ProcessRecord attributedClient = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+ MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, true));
+ ProcessRecord sandboxService = spy(new ProcessRecordBuilder(MOCKAPP_PID,
+ MOCKAPP_SDK_SANDBOX_UID, MOCKAPP_SDK_SANDBOX_PROCESSNAME, MOCKAPP_PACKAGENAME)
+ .setSdkSandboxClientAppPackage(MOCKAPP3_PACKAGENAME)
+ .build());
+
+ setProcessesToLru(sandboxService, client, attributedClient);
+
+ client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ attributedClient.mServices.setHasForegroundServices(true, 0, true);
+ bindService(sandboxService, client, attributedClient, null, 0, mock(IBinder.class));
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ updateOomAdj();
+ assertProcStates(client, PROCESS_STATE_PERSISTENT, PERSISTENT_PROC_ADJ,
+ SCHED_GROUP_DEFAULT);
+ assertProcStates(attributedClient, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ SCHED_GROUP_DEFAULT);
+ assertProcStates(sandboxService, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ SCHED_GROUP_DEFAULT);
}
- private ProcessRecord makeProcessRecord(ActivityManagerService service, int pid, int uid,
- String processName, String packageName, long versionCode, int targetSdkVersion,
- long lastActivityTime, long lastPssTime, long nextPssTime, long lastPss, int maxAdj,
- int setRawAdj, int curAdj, int setAdj, int curSchedGroup, int setSchedGroup,
- int curProcState, int repProcState, int curRawProcState, int setProcState,
- int connectionGroup, int connectionImportance, boolean serviceb,
- boolean hasClientActivities, boolean hasForegroundServices, int fgServiceTypes,
- boolean hasForegroundActivities, boolean repForegroundActivities, boolean systemNoUi,
- boolean hasShownUi, boolean hasTopUi, boolean hasOverlayUi,
- boolean runningRemoteAnimation, boolean hasAboveClient, boolean treatLikeActivity,
- boolean killedByAm, Object forcingToImportant, int numOfCurReceivers,
- long lastProviderTime, long lastTopTime, boolean cached, int numOfExecutingServices,
- String isolatedEntryPoint, boolean execServicesFg) {
- ApplicationInfo ai = spy(new ApplicationInfo());
- ai.uid = uid;
- ai.packageName = packageName;
- ai.longVersionCode = versionCode;
- ai.targetSdkVersion = targetSdkVersion;
- ProcessRecord app = new ProcessRecord(service, ai, processName, uid);
- final ProcessStateRecord state = app.mState;
- final ProcessServiceRecord services = app.mServices;
- final ProcessReceiverRecord receivers = app.mReceivers;
- final ProcessProfileRecord profile = app.mProfile;
- final ProcessProviderRecord providers = app.mProviders;
- app.makeActive(mock(IApplicationThread.class), sService.mProcessStats);
- app.setLastActivityTime(lastActivityTime);
- app.setKilledByAm(killedByAm);
- app.setIsolatedEntryPoint(isolatedEntryPoint);
- setFieldValue(ProcessRecord.class, app, "mWindowProcessController",
- mock(WindowProcessController.class));
- profile.setLastPssTime(lastPssTime);
- profile.setNextPssTime(nextPssTime);
- profile.setLastPss(lastPss);
- state.setMaxAdj(maxAdj);
- state.setSetRawAdj(setRawAdj);
- state.setCurAdj(curAdj);
- state.setSetAdj(setAdj);
- state.setCurrentSchedulingGroup(curSchedGroup);
- state.setSetSchedGroup(setSchedGroup);
- state.setCurProcState(curProcState);
- state.setReportedProcState(repProcState);
- state.setCurRawProcState(curRawProcState);
- state.setSetProcState(setProcState);
- state.setServiceB(serviceb);
- state.setRepForegroundActivities(repForegroundActivities);
- state.setHasForegroundActivities(hasForegroundActivities);
- state.setSystemNoUi(systemNoUi);
- state.setHasShownUi(hasShownUi);
- state.setHasTopUi(hasTopUi);
- state.setRunningRemoteAnimation(runningRemoteAnimation);
- state.setHasOverlayUi(hasOverlayUi);
- state.setCached(cached);
- state.setLastTopTime(lastTopTime);
- state.setForcingToImportant(forcingToImportant);
- services.setConnectionGroup(connectionGroup);
- services.setConnectionImportance(connectionImportance);
- services.setHasClientActivities(hasClientActivities);
- services.setHasForegroundServices(hasForegroundServices, fgServiceTypes,
- /* hasNoneType=*/false);
- services.setHasAboveClient(hasAboveClient);
- services.setTreatLikeActivity(treatLikeActivity);
- services.setExecServicesFg(execServicesFg);
- for (int i = 0; i < numOfExecutingServices; i++) {
- services.startExecutingService(mock(ServiceRecord.class));
- }
- for (int i = 0; i < numOfCurReceivers; i++) {
- receivers.addCurReceiver(mock(BroadcastRecord.class));
- }
- providers.setLastProviderTime(lastProviderTime);
- return app;
+ private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
+ String packageName, boolean hasShownUi) {
+ return new ProcessRecordBuilder(pid, uid, processName, packageName).setHasShownUi(
+ hasShownUi).build();
}
private ServiceRecord makeServiceRecord(ProcessRecord app) {
@@ -2870,6 +2828,7 @@
record.appInfo = app.info;
setFieldValue(ServiceRecord.class, record, "bindings", new ArrayMap<>());
setFieldValue(ServiceRecord.class, record, "pendingStarts", new ArrayList<>());
+ setFieldValue(ServiceRecord.class, record, "isSdkSandbox", app.isSdkSandbox);
return record;
}
@@ -2892,11 +2851,11 @@
}
private ServiceRecord bindService(ProcessRecord service, ProcessRecord client,
- ServiceRecord record, long bindFlags, IBinder binder) {
+ ProcessRecord attributedClient, ServiceRecord record, long bindFlags, IBinder binder) {
if (record == null) {
record = makeServiceRecord(service);
}
- AppBindRecord binding = new AppBindRecord(record, null, client, null);
+ AppBindRecord binding = new AppBindRecord(record, null, client, attributedClient);
ConnectionRecord cr = spy(new ConnectionRecord(binding,
mock(ActivityServiceConnectionsHolder.class),
mock(IServiceConnection.class), bindFlags,
@@ -2961,4 +2920,140 @@
assertBfsl(app);
}
}
+
+ private static class ProcessRecordBuilder {
+ @SuppressWarnings("UnusedVariable")
+ int mPid;
+ int mUid;
+ String mProcessName;
+ String mPackageName;
+ long mVersionCode = 12345;
+ int mTargetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+ long mLastActivityTime;
+ long mLastPssTime;
+ long mNextPssTime;
+ long mLastPss = 12345;
+ int mMaxAdj = UNKNOWN_ADJ;
+ int mSetRawAdj = UNKNOWN_ADJ;
+ int mCurAdj = UNKNOWN_ADJ;
+ int mSetAdj = CACHED_APP_MAX_ADJ;
+ int mCurSchedGroup = SCHED_GROUP_DEFAULT;
+ int mSetSchedGroup = SCHED_GROUP_DEFAULT;
+ int mCurProcState = PROCESS_STATE_NONEXISTENT;
+ int mRepProcState = PROCESS_STATE_NONEXISTENT;
+ int mCurRawProcState = PROCESS_STATE_NONEXISTENT;
+ int mSetProcState = PROCESS_STATE_NONEXISTENT;
+ int mConnectionGroup = 0;
+ int mConnectionImportance = 0;
+ boolean mServiceb = false;
+ boolean mHasClientActivities = false;
+ boolean mHasForegroundServices = false;
+ int mFgServiceTypes = ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE;
+ boolean mHasForegroundActivities = false;
+ boolean mRepForegroundActivities = false;
+ boolean mSystemNoUi = false;
+ boolean mHasShownUi = false;
+ boolean mHasTopUi = false;
+ boolean mHasOverlayUi = false;
+ boolean mRunningRemoteAnimation = false;
+ boolean mHasAboveClient = false;
+ boolean mTreatLikeActivity = false;
+ boolean mKilledByAm = false;
+ Object mForcingToImportant;
+ int mNumOfCurReceivers = 0;
+ long mLastProviderTime = Long.MIN_VALUE;
+ long mLastTopTime = Long.MIN_VALUE;
+ boolean mCached = true;
+ int mNumOfExecutingServices = 0;
+ String mIsolatedEntryPoint = null;
+ boolean mExecServicesFg = false;
+ String mSdkSandboxClientAppPackage = null;
+
+ ProcessRecordBuilder(int pid, int uid, String processName, String packageName) {
+ mPid = pid;
+ mUid = uid;
+ mProcessName = processName;
+ mPackageName = packageName;
+
+ long now = SystemClock.uptimeMillis();
+ mLastActivityTime = now;
+ mLastPssTime = now;
+ mNextPssTime = now;
+ }
+
+ ProcessRecordBuilder setHasShownUi(boolean hasShownUi) {
+ mHasShownUi = hasShownUi;
+ return this;
+ }
+
+ ProcessRecordBuilder setSdkSandboxClientAppPackage(String sdkSandboxClientAppPackage) {
+ mSdkSandboxClientAppPackage = sdkSandboxClientAppPackage;
+ return this;
+ }
+
+ @SuppressWarnings("GuardedBy")
+ public ProcessRecord build() {
+ ApplicationInfo ai = spy(new ApplicationInfo());
+ ai.uid = mUid;
+ ai.packageName = mPackageName;
+ ai.longVersionCode = mVersionCode;
+ ai.targetSdkVersion = mTargetSdkVersion;
+ doCallRealMethod().when(sService).getPackageManagerInternal();
+ doReturn(null).when(sPackageManagerInternal).getApplicationInfo(
+ eq(mSdkSandboxClientAppPackage), anyLong(), anyInt(), anyInt());
+ ProcessRecord app = new ProcessRecord(sService, ai, mProcessName, mUid,
+ mSdkSandboxClientAppPackage, -1, null);
+ final ProcessStateRecord state = app.mState;
+ final ProcessServiceRecord services = app.mServices;
+ final ProcessReceiverRecord receivers = app.mReceivers;
+ final ProcessProfileRecord profile = app.mProfile;
+ final ProcessProviderRecord providers = app.mProviders;
+ app.makeActive(mock(IApplicationThread.class), sService.mProcessStats);
+ app.setLastActivityTime(mLastActivityTime);
+ app.setKilledByAm(mKilledByAm);
+ app.setIsolatedEntryPoint(mIsolatedEntryPoint);
+ setFieldValue(ProcessRecord.class, app, "mWindowProcessController",
+ mock(WindowProcessController.class));
+ profile.setLastPssTime(mLastPssTime);
+ profile.setNextPssTime(mNextPssTime);
+ profile.setLastPss(mLastPss);
+ state.setMaxAdj(mMaxAdj);
+ state.setSetRawAdj(mSetRawAdj);
+ state.setCurAdj(mCurAdj);
+ state.setSetAdj(mSetAdj);
+ state.setCurrentSchedulingGroup(mCurSchedGroup);
+ state.setSetSchedGroup(mSetSchedGroup);
+ state.setCurProcState(mCurProcState);
+ state.setReportedProcState(mRepProcState);
+ state.setCurRawProcState(mCurRawProcState);
+ state.setSetProcState(mSetProcState);
+ state.setServiceB(mServiceb);
+ state.setRepForegroundActivities(mRepForegroundActivities);
+ state.setHasForegroundActivities(mHasForegroundActivities);
+ state.setSystemNoUi(mSystemNoUi);
+ state.setHasShownUi(mHasShownUi);
+ state.setHasTopUi(mHasTopUi);
+ state.setRunningRemoteAnimation(mRunningRemoteAnimation);
+ state.setHasOverlayUi(mHasOverlayUi);
+ state.setCached(mCached);
+ state.setLastTopTime(mLastTopTime);
+ state.setForcingToImportant(mForcingToImportant);
+ services.setConnectionGroup(mConnectionGroup);
+ services.setConnectionImportance(mConnectionImportance);
+ services.setHasClientActivities(mHasClientActivities);
+ services.setHasForegroundServices(mHasForegroundServices, mFgServiceTypes,
+ /* hasNoneType=*/false);
+ services.setHasAboveClient(mHasAboveClient);
+ services.setTreatLikeActivity(mTreatLikeActivity);
+ services.setExecServicesFg(mExecServicesFg);
+ for (int i = 0; i < mNumOfExecutingServices; i++) {
+ services.startExecutingService(mock(ServiceRecord.class));
+ }
+ for (int i = 0; i < mNumOfCurReceivers; i++) {
+ receivers.addCurReceiver(mock(BroadcastRecord.class));
+ }
+ providers.setLastProviderTime(mLastProviderTime);
+ return app;
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/adaptiveauth/AdaptiveAuthServiceTest.java b/services/tests/servicestests/src/com/android/server/adaptiveauth/AdaptiveAuthServiceTest.java
new file mode 100644
index 0000000..08a6529
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/adaptiveauth/AdaptiveAuthServiceTest.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2024 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 com.android.server.adaptiveauth;
+
+import static android.adaptiveauth.Flags.FLAG_ENABLE_ADAPTIVE_AUTH;
+import static android.adaptiveauth.Flags.FLAG_REPORT_BIOMETRIC_AUTH_ATTEMPTS;
+import static android.security.Flags.FLAG_REPORT_PRIMARY_AUTH_ATTEMPTS;
+
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
+import static com.android.server.adaptiveauth.AdaptiveAuthService.MAX_ALLOWED_FAILED_AUTH_ATTEMPTS;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.hardware.biometrics.AuthenticationStateListener;
+import android.hardware.biometrics.BiometricManager;
+import android.os.RemoteException;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
+import com.android.internal.widget.LockSettingsStateListener;
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * atest FrameworksServicesTests:AdaptiveAuthServiceTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AdaptiveAuthServiceTest {
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ private static final int PRIMARY_USER_ID = 0;
+ private static final int MANAGED_PROFILE_USER_ID = 12;
+ private static final int DEFAULT_COUNT_FAILED_AUTH_ATTEMPTS = 0;
+ private static final int REASON_UNKNOWN = 0; // BiometricRequestConstants.RequestReason
+
+ private Context mContext;
+ private AdaptiveAuthService mAdaptiveAuthService;
+
+ @Mock
+ LockPatternUtils mLockPatternUtils;
+ @Mock
+ private LockSettingsInternal mLockSettings;
+ @Mock
+ private BiometricManager mBiometricManager;
+ @Mock
+ private KeyguardManager mKeyguardManager;
+ @Mock
+ private WindowManagerInternal mWindowManager;
+ @Mock
+ private UserManagerInternal mUserManager;
+
+ @Captor
+ ArgumentCaptor<LockSettingsStateListener> mLockSettingsStateListenerCaptor;
+ @Captor
+ ArgumentCaptor<AuthenticationStateListener> mAuthenticationStateListenerCaptor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mSetFlagsRule.enableFlags(FLAG_ENABLE_ADAPTIVE_AUTH);
+ mSetFlagsRule.enableFlags(FLAG_REPORT_PRIMARY_AUTH_ATTEMPTS);
+ mSetFlagsRule.enableFlags(FLAG_REPORT_BIOMETRIC_AUTH_ATTEMPTS);
+
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
+ when(mContext.getSystemService(KeyguardManager.class)).thenReturn(mKeyguardManager);
+
+ LocalServices.removeServiceForTest(LockSettingsInternal.class);
+ LocalServices.addService(LockSettingsInternal.class, mLockSettings);
+ LocalServices.removeServiceForTest(WindowManagerInternal.class);
+ LocalServices.addService(WindowManagerInternal.class, mWindowManager);
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.addService(UserManagerInternal.class, mUserManager);
+
+ mAdaptiveAuthService = new AdaptiveAuthService(mContext, mLockPatternUtils);
+ mAdaptiveAuthService.init();
+
+ verify(mLockSettings).registerLockSettingsStateListener(
+ mLockSettingsStateListenerCaptor.capture());
+ verify(mBiometricManager).registerAuthenticationStateListener(
+ mAuthenticationStateListenerCaptor.capture());
+
+ // Set PRIMARY_USER_ID as the parent of MANAGED_PROFILE_USER_ID
+ when(mUserManager.getProfileParentId(eq(MANAGED_PROFILE_USER_ID)))
+ .thenReturn(PRIMARY_USER_ID);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ LocalServices.removeServiceForTest(LockSettingsInternal.class);
+ LocalServices.removeServiceForTest(WindowManagerInternal.class);
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ }
+
+ @Test
+ public void testReportAuthAttempt_primaryAuthSucceeded()
+ throws RemoteException {
+ mLockSettingsStateListenerCaptor.getValue().onAuthenticationSucceeded(PRIMARY_USER_ID);
+ waitForAuthCompletion();
+
+ verifyNotLockDevice(DEFAULT_COUNT_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+ PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void testReportAuthAttempt_primaryAuthFailed_once()
+ throws RemoteException {
+ mLockSettingsStateListenerCaptor.getValue().onAuthenticationFailed(PRIMARY_USER_ID);
+ waitForAuthCompletion();
+
+ verifyNotLockDevice(1 /* expectedCntFailedAttempts */, PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void testReportAuthAttempt_primaryAuthFailed_multiple_deviceCurrentlyLocked()
+ throws RemoteException {
+ // Device is currently locked and Keyguard is showing
+ when(mKeyguardManager.isDeviceLocked(PRIMARY_USER_ID)).thenReturn(true);
+ when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
+
+ for (int i = 0; i < MAX_ALLOWED_FAILED_AUTH_ATTEMPTS; i++) {
+ mLockSettingsStateListenerCaptor.getValue().onAuthenticationFailed(PRIMARY_USER_ID);
+ }
+ waitForAuthCompletion();
+
+ verifyNotLockDevice(MAX_ALLOWED_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+ PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void testReportAuthAttempt_primaryAuthFailed_multiple_deviceCurrentlyNotLocked()
+ throws RemoteException {
+ // Device is currently not locked and Keyguard is not showing
+ when(mKeyguardManager.isDeviceLocked(PRIMARY_USER_ID)).thenReturn(false);
+ when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
+
+ for (int i = 0; i < MAX_ALLOWED_FAILED_AUTH_ATTEMPTS; i++) {
+ mLockSettingsStateListenerCaptor.getValue().onAuthenticationFailed(PRIMARY_USER_ID);
+ }
+ waitForAuthCompletion();
+
+ verifyLockDevice(PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void testReportAuthAttempt_biometricAuthSucceeded()
+ throws RemoteException {
+ mAuthenticationStateListenerCaptor.getValue()
+ .onAuthenticationSucceeded(REASON_UNKNOWN, PRIMARY_USER_ID);
+ waitForAuthCompletion();
+
+ verifyNotLockDevice(DEFAULT_COUNT_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+ PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void testReportAuthAttempt_biometricAuthFailed_once()
+ throws RemoteException {
+ mAuthenticationStateListenerCaptor.getValue()
+ .onAuthenticationFailed(REASON_UNKNOWN, PRIMARY_USER_ID);
+ waitForAuthCompletion();
+
+ verifyNotLockDevice(1 /* expectedCntFailedAttempts */, PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void testReportAuthAttempt_biometricAuthFailed_multiple_deviceCurrentlyLocked()
+ throws RemoteException {
+ // Device is currently locked and Keyguard is showing
+ when(mKeyguardManager.isDeviceLocked(PRIMARY_USER_ID)).thenReturn(true);
+ when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
+
+ for (int i = 0; i < MAX_ALLOWED_FAILED_AUTH_ATTEMPTS; i++) {
+ mAuthenticationStateListenerCaptor.getValue()
+ .onAuthenticationFailed(REASON_UNKNOWN, PRIMARY_USER_ID);
+ }
+ waitForAuthCompletion();
+
+ verifyNotLockDevice(MAX_ALLOWED_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+ PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void testReportAuthAttempt_biometricAuthFailed_multiple_deviceCurrentlyNotLocked()
+ throws RemoteException {
+ // Device is currently not locked and Keyguard is not showing
+ when(mKeyguardManager.isDeviceLocked(PRIMARY_USER_ID)).thenReturn(false);
+ when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
+
+ for (int i = 0; i < MAX_ALLOWED_FAILED_AUTH_ATTEMPTS; i++) {
+ mAuthenticationStateListenerCaptor.getValue()
+ .onAuthenticationFailed(REASON_UNKNOWN, PRIMARY_USER_ID);
+ }
+ waitForAuthCompletion();
+
+ verifyLockDevice(PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void testReportAuthAttempt_biometricAuthFailedThenPrimaryAuthSucceeded()
+ throws RemoteException {
+ // Three failed biometric auth attempts
+ for (int i = 0; i < 3; i++) {
+ mAuthenticationStateListenerCaptor.getValue()
+ .onAuthenticationFailed(REASON_UNKNOWN, PRIMARY_USER_ID);
+ }
+ // One successful primary auth attempt
+ mLockSettingsStateListenerCaptor.getValue().onAuthenticationSucceeded(PRIMARY_USER_ID);
+ waitForAuthCompletion();
+
+ verifyNotLockDevice(DEFAULT_COUNT_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+ PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void testReportAuthAttempt_primaryAuthFailedThenBiometricAuthSucceeded()
+ throws RemoteException {
+ // Three failed primary auth attempts
+ for (int i = 0; i < 3; i++) {
+ mLockSettingsStateListenerCaptor.getValue().onAuthenticationFailed(PRIMARY_USER_ID);
+ }
+ // One successful biometric auth attempt
+ mAuthenticationStateListenerCaptor.getValue()
+ .onAuthenticationSucceeded(REASON_UNKNOWN, PRIMARY_USER_ID);
+ waitForAuthCompletion();
+
+ verifyNotLockDevice(DEFAULT_COUNT_FAILED_AUTH_ATTEMPTS /* expectedCntFailedAttempts */,
+ PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void testReportAuthAttempt_primaryAuthAndBiometricAuthFailed_primaryUser()
+ throws RemoteException {
+ // Three failed primary auth attempts
+ for (int i = 0; i < 3; i++) {
+ mLockSettingsStateListenerCaptor.getValue().onAuthenticationFailed(PRIMARY_USER_ID);
+ }
+ // Two failed biometric auth attempts
+ for (int i = 0; i < 2; i++) {
+ mAuthenticationStateListenerCaptor.getValue()
+ .onAuthenticationFailed(REASON_UNKNOWN, PRIMARY_USER_ID);
+ }
+ waitForAuthCompletion();
+
+ verifyLockDevice(PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void testReportAuthAttempt_primaryAuthAndBiometricAuthFailed_profileOfPrimaryUser()
+ throws RemoteException {
+ // Three failed primary auth attempts
+ for (int i = 0; i < 3; i++) {
+ mLockSettingsStateListenerCaptor.getValue()
+ .onAuthenticationFailed(MANAGED_PROFILE_USER_ID);
+ }
+ // Two failed biometric auth attempts
+ for (int i = 0; i < 2; i++) {
+ mAuthenticationStateListenerCaptor.getValue()
+ .onAuthenticationFailed(REASON_UNKNOWN, MANAGED_PROFILE_USER_ID);
+ }
+ waitForAuthCompletion();
+
+ verifyLockDevice(MANAGED_PROFILE_USER_ID);
+ }
+
+ private void verifyNotLockDevice(int expectedCntFailedAttempts, int userId) {
+ assertEquals(expectedCntFailedAttempts,
+ mAdaptiveAuthService.mFailedAttemptsForUser.get(userId));
+ verify(mWindowManager, never()).lockNow();
+ }
+
+ private void verifyLockDevice(int userId) {
+ assertEquals(MAX_ALLOWED_FAILED_AUTH_ATTEMPTS,
+ mAdaptiveAuthService.mFailedAttemptsForUser.get(userId));
+ verify(mLockPatternUtils).requireStrongAuth(
+ eq(SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST), eq(userId));
+ // If userId is MANAGED_PROFILE_USER_ID, the StrongAuthFlag of its parent (PRIMARY_USER_ID)
+ // should also be verified
+ if (userId == MANAGED_PROFILE_USER_ID) {
+ verify(mLockPatternUtils).requireStrongAuth(
+ eq(SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST), eq(PRIMARY_USER_ID));
+ }
+ verify(mWindowManager).lockNow();
+ }
+
+ /**
+ * Wait for all auth events to complete before verification
+ */
+ private static void waitForAuthCompletion() {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/adaptiveauth/OWNERS b/services/tests/servicestests/src/com/android/server/adaptiveauth/OWNERS
new file mode 100644
index 0000000..0218a78
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/adaptiveauth/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/adaptiveauth/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index aefa6de..abd3abe 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -75,12 +75,12 @@
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.internal.util.test.LocalServiceKeeperRule;
+import com.android.server.LocalServices;
import com.android.server.testutils.OffsettableClock;
import com.android.server.wm.WindowManagerInternal;
+import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -164,17 +164,15 @@
@Captor
private ArgumentCaptor<ContentRecordingSession> mSessionCaptor;
- @Rule
- public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule();
-
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
when(mWatcherCallback.asBinder()).thenReturn(new Binder());
- mLocalServiceKeeperRule.overrideLocalService(ActivityManagerInternal.class, mAmInternal);
- mLocalServiceKeeperRule.overrideLocalService(WindowManagerInternal.class,
- mWindowManagerInternal);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.addService(ActivityManagerInternal.class, mAmInternal);
+ LocalServices.removeServiceForTest(WindowManagerInternal.class);
+ LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
mContext = spy(new ContextWrapper(
InstrumentationRegistry.getInstrumentation().getTargetContext()));
@@ -189,6 +187,12 @@
mService = new MediaProjectionManagerService(mContext);
}
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.removeServiceForTest(WindowManagerInternal.class);
+ }
+
@Test
public void testGetActiveProjectionInfoInternal() throws NameNotFoundException {
assertThat(mService.getActiveProjectionInfo()).isNull();
@@ -384,16 +388,16 @@
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
service);
// No starts yet, and not timed out yet - so still valid.
- assertThat(projection.isValidInternal()).isTrue();
+ assertThat(projection.isValid()).isTrue();
// Only one start - so still valid.
projection.start(mIMediaProjectionCallback);
- assertThat(projection.isValidInternal()).isTrue();
+ assertThat(projection.isValid()).isTrue();
// Second start - technically allowed to start again, without stopping in between.
// Token should no longer be valid.
projection.start(mIMediaProjectionCallback);
- assertThat(projection.isValidInternal()).isFalse();
+ assertThat(projection.isValid()).isFalse();
}
@Test
@@ -403,17 +407,17 @@
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
service);
// No starts yet, and not timed out yet - so still valid.
- assertThat(projection.isValidInternal()).isTrue();
+ assertThat(projection.isValid()).isTrue();
// Only one start - so still valid.
projection.start(mIMediaProjectionCallback);
- assertThat(projection.isValidInternal()).isTrue();
+ assertThat(projection.isValid()).isTrue();
projection.stop();
// Second start - so not valid.
projection.start(mIMediaProjectionCallback);
- assertThat(projection.isValidInternal()).isFalse();
+ assertThat(projection.isValid()).isFalse();
}
@Test
@@ -438,7 +442,7 @@
mClock.fastForward(projection.mDefaultTimeoutMs + 10);
// Immediate timeout - so no longer valid.
- assertThat(projection.isValidInternal()).isFalse();
+ assertThat(projection.isValid()).isFalse();
}
@Test
@@ -448,10 +452,10 @@
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(
service);
// Simulate MediaProjection#createVirtualDisplay being invoked previously.
- projection.notifyVirtualDisplayCreatedInternal(10);
+ projection.notifyVirtualDisplayCreated(10);
// Trying to re-use token on another MediaProjection#createVirtualDisplay - no longer valid.
- assertThat(projection.isValidInternal()).isFalse();
+ assertThat(projection.isValid()).isFalse();
}
// TODO(269273190): Test flag using compat annotations instead.
@@ -467,7 +471,7 @@
// Second start - so not valid.
projection.start(mIMediaProjectionCallback);
- assertThrows(SecurityException.class, projection::isValidInternal);
+ assertThrows(SecurityException.class, projection::isValid);
}
// TODO(269273190): Test flag using compat annotations instead.
@@ -484,7 +488,7 @@
// Second start - so not valid.
projection.start(mIMediaProjectionCallback);
- assertThat(projection.isValidInternal()).isFalse();
+ assertThat(projection.isValid()).isFalse();
}
@Test
@@ -623,7 +627,7 @@
mService.setUserReviewGrantedConsentResult(RECORD_CONTENT_DISPLAY, projection);
// Virtual Display is finally created.
- projection.notifyVirtualDisplayCreatedInternal(10);
+ projection.notifyVirtualDisplayCreated(10);
verifySetSessionWithContent(ContentRecordingSession.RECORD_CONTENT_DISPLAY);
}
@@ -726,7 +730,7 @@
throws Exception {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
projection.start(mIMediaProjectionCallback);
- projection.notifyVirtualDisplayCreatedInternal(10);
+ projection.notifyVirtualDisplayCreated(10);
// Waiting for user to review consent.
assertThat(mService.isCurrentProjection(projection)).isTrue();
doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
@@ -781,9 +785,9 @@
@RecordContent int recordedContent)
throws NameNotFoundException {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
- projection.setLaunchCookieInternal(new LaunchCookie());
+ projection.setLaunchCookie(new LaunchCookie());
projection.start(mIMediaProjectionCallback);
- projection.notifyVirtualDisplayCreatedInternal(10);
+ projection.notifyVirtualDisplayCreated(10);
// Waiting for user to review consent.
doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
any(ContentRecordingSession.class));
@@ -804,7 +808,7 @@
throws NameNotFoundException {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
projection.start(mIMediaProjectionCallback);
- projection.notifyVirtualDisplayCreatedInternal(10);
+ projection.notifyVirtualDisplayCreated(10);
// Waiting for user to review consent.
doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
eq(mWaitingDisplaySession));
@@ -822,7 +826,7 @@
public void testSetUserReviewGrantedConsentResult_displayMirroring_noPriorSession()
throws NameNotFoundException {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
- projection.setLaunchCookieInternal(new LaunchCookie());
+ projection.setLaunchCookie(new LaunchCookie());
projection.start(mIMediaProjectionCallback);
// Skip setting the prior session details.
@@ -841,7 +845,7 @@
public void testSetUserReviewGrantedConsentResult_displayMirroring_sessionNotWaiting()
throws NameNotFoundException {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
- projection.setLaunchCookieInternal(new LaunchCookie());
+ projection.setLaunchCookie(new LaunchCookie());
projection.start(mIMediaProjectionCallback);
// Session is not waiting for user's consent.
doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 847c9d0..d5eeaa7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1561,7 +1561,7 @@
.build();
final int result = starter.recycleTask(task, null, null, null,
- BalVerdict.ALLOW_BY_DEFAULT);
+ BalVerdict.ALLOW_PRIVILEGED);
assertThat(result == START_SUCCESS).isTrue();
assertThat(starter.mAddingToTask).isTrue();
}
@@ -2075,7 +2075,7 @@
starter.startActivityInner(target, source, null /* voiceSession */,
null /* voiceInteractor */, 0 /* startFlags */,
options, inTask, inTaskFragment,
- BalVerdict.ALLOW_BY_DEFAULT,
+ BalVerdict.ALLOW_PRIVILEGED,
null /* intentGrants */, -1 /* realCallingUid */);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 60dfe6f..887e5ee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -811,7 +811,7 @@
@Test
public void testDisplayContentUpdatesRecording_withSurface() {
- createContentRecorder(createDefaultDisplayInfo());
+ defaultInit();
// GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
// mirror.
setUpDefaultTaskDisplayAreaWindowToken();
@@ -820,7 +820,6 @@
// getDisplaySurfaceDefaultSize (done by surfaceControlMirrors in setUp).
final DisplayContent virtualDisplay =
mRootWindowContainer.getDisplayContent(mDisplaySession.getVirtualDisplayId());
- virtualDisplay.setContentRecorder(mContentRecorder);
mWm.mContentRecordingController.setContentRecordingSessionLocked(mDisplaySession, mWm);
virtualDisplay.updateRecording();
@@ -845,7 +844,6 @@
// WHEN getting the DisplayContent for the new virtual display.
final DisplayContent virtualDisplay =
mRootWindowContainer.getDisplayContent(mDisplaySession.getVirtualDisplayId());
- virtualDisplay.setContentRecorder(mContentRecorder);
// Return the default display as the value to mirror to ensure the VD with flag mirroring
// creates a ContentRecordingSession automatically.
doReturn(DEFAULT_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
index 42004c3..c84fe08 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
@@ -24,7 +24,6 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import android.platform.test.annotations.Presubmit;
@@ -32,8 +31,6 @@
import androidx.test.filters.SmallTest;
-import com.android.server.wm.ContentRecorder.MediaProjectionManagerWrapper;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -71,11 +68,6 @@
mVirtualDisplayId = mVirtualDisplayContent.getDisplayId();
mWm.mRoot.onDisplayAdded(mVirtualDisplayId);
spyOn(mVirtualDisplayContent);
- final MediaProjectionManagerWrapper
- mediaProjectionManagerWrapper = mock(MediaProjectionManagerWrapper.class);
- final ContentRecorder contentRecorder = new ContentRecorder(mVirtualDisplayContent,
- mediaProjectionManagerWrapper, /* correctForAnisotropicPixels= */ false);
- mVirtualDisplayContent.setContentRecorder(contentRecorder);
mDefaultSession.setVirtualDisplayId(mVirtualDisplayId);
mWaitingDisplaySession.setVirtualDisplayId(mVirtualDisplayId);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
index c404c77..bb5887d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -187,7 +187,7 @@
/* options */null,
/* inTask */null,
/* inTaskFragment */ null,
- BalVerdict.ALLOW_BY_DEFAULT,
+ BalVerdict.ALLOW_PRIVILEGED,
/* intentGrants */null,
/* realCaiingUid */ -1);
@@ -217,7 +217,7 @@
/* options= */null,
/* inTask= */null,
/* inTaskFragment= */ null,
- BalVerdict.ALLOW_BY_DEFAULT,
+ BalVerdict.ALLOW_PRIVILEGED,
/* intentGrants= */null,
/* realCaiingUid */ -1);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 8b0fc2c..cd3ce91 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -1424,6 +1424,25 @@
assertFalse(window2.isSecureLocked());
}
+ @Test
+ @RequiresFlagsEnabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION)
+ public void testIsSecureLocked_sensitiveContentBlockOrClearScreenCaptureForApp() {
+ String testPackage = "test";
+ int ownerId = 20;
+ final WindowState window = createWindow(null, TYPE_APPLICATION, "window", ownerId);
+ window.mAttrs.packageName = testPackage;
+ assertFalse(window.isSecureLocked());
+
+ PackageInfo blockedPackage = new PackageInfo(testPackage, ownerId);
+ ArraySet<PackageInfo> blockedPackages = new ArraySet();
+ blockedPackages.add(blockedPackage);
+ mWm.mSensitiveContentPackages.addBlockScreenCaptureForApps(blockedPackages);
+ assertTrue(window.isSecureLocked());
+
+ mWm.mSensitiveContentPackages.removeBlockScreenCaptureForApps(blockedPackages);
+ assertFalse(window.isSecureLocked());
+ }
+
private static class TestImeTargetChangeListener implements ImeTargetChangeListener {
private IBinder mImeTargetToken;
private boolean mIsRemoved;
diff --git a/telecomm/java/android/telecom/CallAttributes.java b/telecomm/java/android/telecom/CallAttributes.java
index 8c6e101..afd34fc 100644
--- a/telecomm/java/android/telecom/CallAttributes.java
+++ b/telecomm/java/android/telecom/CallAttributes.java
@@ -16,6 +16,7 @@
package android.telecom;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -24,6 +25,8 @@
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.server.telecom.flags.Flags;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -113,7 +116,8 @@
public static final int VIDEO_CALL = 2;
/** @hide */
- @IntDef(value = {SUPPORTS_SET_INACTIVE, SUPPORTS_STREAM, SUPPORTS_TRANSFER}, flag = true)
+ @IntDef(value = {SUPPORTS_SET_INACTIVE, SUPPORTS_STREAM, SUPPORTS_TRANSFER,
+ SUPPORTS_VIDEO_CALLING}, flag = true)
@Retention(RetentionPolicy.SOURCE)
public @interface CallCapability {
}
@@ -133,6 +137,12 @@
* The call can be completely transferred from one endpoint to another.
*/
public static final int SUPPORTS_TRANSFER = 1 << 3;
+ /**
+ * The call supports video calling. This allows clients to gate video calling on a per call
+ * basis as opposed to re-registering the phone account.
+ */
+ @FlaggedApi(Flags.FLAG_TRANSACTIONAL_VIDEO_STATE)
+ public static final int SUPPORTS_VIDEO_CALLING = 1 << 4;
/**
* Build an instance of {@link CallAttributes}. In order to build a valid instance, a
diff --git a/telecomm/java/android/telecom/CallControl.java b/telecomm/java/android/telecom/CallControl.java
index a1407869..808a575 100644
--- a/telecomm/java/android/telecom/CallControl.java
+++ b/telecomm/java/android/telecom/CallControl.java
@@ -293,12 +293,50 @@
try {
mServerInterface.setMuteState(isMuted,
new CallControlResultReceiver("requestMuteState", executor, callback));
-
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
+ /**
+ * Request a new video state for the ongoing call. This can only be changed if the application
+ * has registered a {@link PhoneAccount} with the
+ * {@link PhoneAccount#CAPABILITY_SUPPORTS_VIDEO_CALLING} and set the
+ * {@link CallAttributes#SUPPORTS_VIDEO_CALLING} when adding the call via
+ * {@link TelecomManager#addCall(CallAttributes, Executor, OutcomeReceiver,
+ * CallControlCallback, CallEventCallback)}
+ *
+ * @param videoState to report to Telecom. To see the valid argument to pass,
+ * see {@link CallAttributes.CallType}.
+ * @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
+ * will be called on.
+ * @param callback that will be completed on the Telecom side that details success or failure
+ * of the requested operation.
+ *
+ * {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
+ * switched the video state.
+ *
+ * {@link OutcomeReceiver#onError} will be called if Telecom has failed to set
+ * the new video state. A {@link CallException} will be passed
+ * that details why the operation failed.
+ * @throws IllegalArgumentException if the argument passed for videoState is invalid. To see a
+ * list of valid states, see {@link CallAttributes.CallType}.
+ */
+ @FlaggedApi(Flags.FLAG_TRANSACTIONAL_VIDEO_STATE)
+ public void requestVideoState(@CallAttributes.CallType int videoState,
+ @CallbackExecutor @NonNull Executor executor,
+ @NonNull OutcomeReceiver<Void, CallException> callback) {
+ validateVideoState(videoState);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+ try {
+ mServerInterface.requestVideoState(videoState, mCallId,
+ new CallControlResultReceiver("requestVideoState", executor, callback));
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
/**
* Raises an event to the {@link android.telecom.InCallService} implementations tracking this
* call via {@link android.telecom.Call.Callback#onConnectionEvent(Call, String, Bundle)}.
diff --git a/telecomm/java/android/telecom/CallEventCallback.java b/telecomm/java/android/telecom/CallEventCallback.java
index a41c011..b0438bf 100644
--- a/telecomm/java/android/telecom/CallEventCallback.java
+++ b/telecomm/java/android/telecom/CallEventCallback.java
@@ -16,9 +16,12 @@
package android.telecom;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.os.Bundle;
+import com.android.server.telecom.flags.Flags;
+
import java.util.List;
/**
@@ -51,6 +54,14 @@
void onMuteStateChanged(boolean isMuted);
/**
+ * Called when the video state changes.
+ *
+ * @param videoState The current video state.
+ */
+ @FlaggedApi(Flags.FLAG_TRANSACTIONAL_VIDEO_STATE)
+ default void onVideoStateChanged(@CallAttributes.CallType int videoState) {}
+
+ /**
* Telecom is informing the client user requested call streaming but the stream can't be
* started.
*
diff --git a/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java b/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java
index 467e89c..a2c6086 100644
--- a/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java
+++ b/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java
@@ -33,6 +33,8 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.server.telecom.flags.Flags;
+
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -148,6 +150,7 @@
private static final String ON_REQ_ENDPOINT_CHANGE = "onRequestEndpointChange";
private static final String ON_AVAILABLE_CALL_ENDPOINTS = "onAvailableCallEndpointsChanged";
private static final String ON_MUTE_STATE_CHANGED = "onMuteStateChanged";
+ private static final String ON_VIDEO_STATE_CHANGED = "onVideoStateChanged";
private static final String ON_CALL_STREAMING_FAILED = "onCallStreamingFailed";
private static final String ON_EVENT = "onEvent";
@@ -261,6 +264,11 @@
handleEventCallback(callId, ON_MUTE_STATE_CHANGED, isMuted);
}
+ @Override
+ public void onVideoStateChanged(String callId, int videoState) {
+ handleEventCallback(callId, ON_VIDEO_STATE_CHANGED, videoState);
+ }
+
public void handleEventCallback(String callId, String action, Object arg) {
Log.d(TAG, TextUtils.formatSimple("hEC: [%s], callId=[%s]", action, callId));
// lookup the callEventCallback associated with the particular call
@@ -281,6 +289,11 @@
case ON_MUTE_STATE_CHANGED:
callback.onMuteStateChanged((boolean) arg);
break;
+ case ON_VIDEO_STATE_CHANGED:
+ if (Flags.transactionalVideoState()) {
+ callback.onVideoStateChanged((int) arg);
+ }
+ break;
case ON_CALL_STREAMING_FAILED:
callback.onCallStreamingFailed((int) arg /* reason */);
break;
diff --git a/telecomm/java/com/android/internal/telecom/ICallControl.aidl b/telecomm/java/com/android/internal/telecom/ICallControl.aidl
index 372e4a12..ac49660 100644
--- a/telecomm/java/com/android/internal/telecom/ICallControl.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallControl.aidl
@@ -34,4 +34,5 @@
void requestCallEndpointChange(in CallEndpoint callEndpoint, in ResultReceiver callback);
void setMuteState(boolean isMuted, in ResultReceiver callback);
void sendEvent(String callId, String event, in Bundle extras);
+ void requestVideoState(int videoState, String callId, in ResultReceiver callback);
}
\ No newline at end of file
diff --git a/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl b/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl
index 213cafb..e4d6b0c 100644
--- a/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl
@@ -45,6 +45,8 @@
void onCallEndpointChanged(String callId, in CallEndpoint endpoint);
void onAvailableCallEndpointsChanged(String callId, in List<CallEndpoint> endpoint);
void onMuteStateChanged(String callId, boolean isMuted);
+ // -- Video Related
+ void onVideoStateChanged(String callId, int videoState);
// -- Events
void onEvent(String callId, String event, in Bundle extras);
// hidden methods that help with cleanup
diff --git a/telephony/java/android/telephony/DomainSelectionService.java b/telephony/java/android/telephony/DomainSelectionService.java
index 4ff9712..633694a 100644
--- a/telephony/java/android/telephony/DomainSelectionService.java
+++ b/telephony/java/android/telephony/DomainSelectionService.java
@@ -20,6 +20,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
@@ -855,7 +856,8 @@
*
* @return an {@link Executor} used to execute methods called remotely by the framework.
*/
- public @NonNull Executor onCreateExecutor() {
+ @SuppressLint("OnNameExpected")
+ public @NonNull Executor getCreateExecutor() {
return Runnable::run;
}
@@ -869,7 +871,7 @@
public final @NonNull Executor getCachedExecutor() {
synchronized (mExecutorLock) {
if (mExecutor == null) {
- Executor e = onCreateExecutor();
+ Executor e = getCreateExecutor();
mExecutor = (e != null) ? e : Runnable::run;
}
return mExecutor;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 041822b..fd9aae9 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -15011,6 +15011,27 @@
}
/**
+ * Get the emergency assistance package name.
+ *
+ * @return the package name of the emergency assistance app.
+ * @throws IllegalStateException if emergency assistance is not enabled.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @FlaggedApi(android.permission.flags.Flags.FLAG_GET_EMERGENCY_ROLE_HOLDER_API_ENABLED)
+ @NonNull
+ @SystemApi
+ public String getEmergencyAssistancePackage() {
+ if (!isEmergencyAssistanceEnabled()) {
+ throw new IllegalStateException("isEmergencyAssistanceEnabled() is false.");
+ }
+ String emergencyRole = mContext.getSystemService(RoleManager.class)
+ .getEmergencyRoleHolder(mContext.getUserId());
+ return Objects.requireNonNull(emergencyRole, "Emergency role holder must not be null");
+ }
+
+ /**
* Get the emergency number list based on current locale, sim, default, modem and network.
*
* <p>In each returned list, the emergency number {@link EmergencyNumber} coming from higher
diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh
deleted file mode 100755
index a6847ae..0000000
--- a/tools/hoststubgen/scripts/run-all-tests.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2023 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.
-
-source "${0%/*}"/../common.sh
-
-# Move to the top directory of hoststubgen
-cd ..
-
-ATEST_ARGS="--host"
-
-# These tests are known to pass.
-READY_TEST_MODULES=(
- hoststubgen-test-tiny-test
- CtsUtilTestCasesRavenwood
- CtsOsTestCasesRavenwood # This one uses native sustitution, so let's run it too.
-)
-
-MUST_BUILD_MODULES=(
- "${NOT_READY_TEST_MODULES[*]}"
-)
-
-# First, build all the test / etc modules. This shouldn't fail.
-run m "${MUST_BUILD_MODULES[@]}"
-
-# Run the hoststubgen unittests / etc
-run atest $ATEST_ARGS hoststubgentest hoststubgen-invoke-test
-
-# Next, run the golden check. This should always pass too.
-# The following scripts _should_ pass too, but they depend on the internal paths to soong generated
-# files, and they may fail when something changes in the build system.
-run ./hoststubgen/test-tiny-framework/diff-and-update-golden.sh
-
-run ./hoststubgen/test-tiny-framework/run-test-manually.sh
-run atest $ATEST_ARGS tiny-framework-dump-test
-
-# This script is already broken on goog/master
-# run ./scripts/build-framework-hostside-jars-without-genrules.sh
-
-# These tests should all pass.
-run atest $ATEST_ARGS ${READY_TEST_MODULES[*]}
-
-echo ""${0##*/}" finished, with no failures. Ready to submit!"