summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt12
-rw-r--r--core/api/system-current.txt10
-rw-r--r--core/api/test-current.txt20
-rw-r--r--core/java/android/animation/Animator.java2
-rw-r--r--core/java/android/app/ActivityThread.java20
-rw-r--r--core/java/android/app/Notification.java9
-rw-r--r--core/java/android/app/admin/AccountTypePolicyKey.java2
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java22
-rw-r--r--core/java/android/app/admin/IntentFilterPolicyKey.java2
-rw-r--r--core/java/android/app/admin/PackagePermissionPolicyKey.java2
-rw-r--r--core/java/android/app/admin/PackagePolicyKey.java2
-rw-r--r--core/java/android/app/admin/UserRestrictionPolicyKey.java2
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java39
-rw-r--r--core/java/android/hardware/input/InputDeviceLightsManager.java21
-rw-r--r--core/java/android/hardware/input/InputDeviceVibrator.java16
-rw-r--r--core/java/android/hardware/input/InputDeviceVibratorManager.java14
-rw-r--r--core/java/android/hardware/input/InputManager.java160
-rw-r--r--core/java/android/hardware/input/InputManagerGlobal.java154
-rw-r--r--core/java/android/provider/Settings.java35
-rw-r--r--core/java/android/security/net/config/SystemCertificateSource.java8
-rw-r--r--core/java/android/view/IWindowSession.aidl15
-rw-r--r--core/java/android/view/WindowManager.java134
-rw-r--r--core/java/android/view/WindowlessWindowManager.java32
-rw-r--r--core/java/android/widget/PopupWindow.java4
-rw-r--r--core/java/android/widget/Toast.java3
-rw-r--r--core/res/AndroidManifest.xml3
-rw-r--r--core/res/res/values/config.xml15
-rw-r--r--core/tests/coretests/src/android/view/inputmethod/DeleteRangeGestureTest.java59
-rw-r--r--core/tests/coretests/src/android/view/inputmethod/InsertGestureTest.java56
-rw-r--r--core/tests/coretests/src/android/view/inputmethod/InsertModeGestureTest.java57
-rw-r--r--core/tests/coretests/src/android/view/inputmethod/SelectGestureTest.java55
-rw-r--r--core/tests/coretests/src/android/view/inputmethod/SelectRangeGestureTest.java59
-rw-r--r--data/etc/services.core.protolog.json90
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml4
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java2
-rw-r--r--libs/input/MouseCursorController.cpp18
-rw-r--r--libs/input/MouseCursorController.h4
-rw-r--r--libs/input/PointerController.cpp8
-rw-r--r--libs/input/PointerController.h28
-rw-r--r--media/java/android/media/tv/ITvInputSessionWrapper.java2
-rw-r--r--media/java/android/media/tv/TvInputService.java4
-rw-r--r--packages/SettingsLib/DeviceStateRotationLock/Android.bp5
-rw-r--r--packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java111
-rw-r--r--packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt55
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt11
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java17
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt317
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt16
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt238
-rw-r--r--packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java48
-rw-r--r--packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginListener.java86
-rw-r--r--packages/SystemUI/res/layout/notification_conversation_info.xml4
-rw-r--r--packages/SystemUI/res/values/flags.xml3
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt9
-rw-r--r--packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt21
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java206
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSHost.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractor.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt76
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt86
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java199
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java18
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/core/java/com/android/server/biometrics/TEST_MAPPING23
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java3
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssConfiguration.java2
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java34
-rw-r--r--services/core/java/com/android/server/pm/ReconcilePackageUtils.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java60
-rw-r--r--services/core/java/com/android/server/wm/DragState.java7
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java19
-rw-r--r--services/core/java/com/android/server/wm/Session.java13
-rw-r--r--services/core/java/com/android/server/wm/Task.java35
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java211
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java201
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java11
-rw-r--r--services/core/jni/gnss/GnssConfiguration.cpp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java143
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java162
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java164
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java188
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java40
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java105
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java7
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java88
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java46
-rw-r--r--telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl17
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteManager.java23
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java20
-rw-r--r--tests/Input/Android.bp3
-rw-r--r--tests/Input/src/com/android/test/input/AnrTest.kt2
-rw-r--r--tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt3
-rw-r--r--tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt1
-rw-r--r--tools/lint/framework/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt927
-rw-r--r--tools/lint/framework/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt569
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java38
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java4
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java35
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java4
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java34
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java5
-rw-r--r--wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java13
-rw-r--r--wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java14
-rw-r--r--wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java13
141 files changed, 3227 insertions, 3325 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 02de1cd9a137..771d56cd1987 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6623,6 +6623,7 @@ package android.app {
ctor public Notification.MediaStyle();
ctor @Deprecated public Notification.MediaStyle(android.app.Notification.Builder);
method public android.app.Notification.MediaStyle setMediaSession(android.media.session.MediaSession.Token);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public android.app.Notification.MediaStyle setRemotePlaybackInfo(@NonNull CharSequence, @DrawableRes int, @Nullable android.app.PendingIntent);
method public android.app.Notification.MediaStyle setShowActionsInCompactView(int...);
}
@@ -8049,6 +8050,7 @@ package android.app.admin {
field public static final String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
field public static final String ACTION_CHECK_POLICY_COMPLIANCE = "android.app.action.CHECK_POLICY_COMPLIANCE";
field public static final String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
+ field public static final String ACTION_DEVICE_FINANCING_STATE_CHANGED = "android.app.admin.action.DEVICE_FINANCING_STATE_CHANGED";
field public static final String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
field public static final String ACTION_DEVICE_POLICY_RESOURCE_UPDATED = "android.app.action.DEVICE_POLICY_RESOURCE_UPDATED";
field public static final String ACTION_GET_PROVISIONING_MODE = "android.app.action.GET_PROVISIONING_MODE";
@@ -27478,7 +27480,7 @@ package android.media.tv {
method public boolean onTrackballEvent(android.view.MotionEvent);
method public abstract boolean onTune(android.net.Uri);
method public boolean onTune(android.net.Uri, android.os.Bundle);
- method public void onTvMessage(@NonNull String, @NonNull android.os.Bundle);
+ method public void onTvMessage(int, @NonNull android.os.Bundle);
method public void onUnblockContent(android.media.tv.TvContentRating);
method public void setOverlayViewEnabled(boolean);
}
@@ -53907,6 +53909,14 @@ package android.view {
method public void removeViewImmediate(android.view.View);
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 public static final String PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION = "android.window.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION";
+ field public static final String PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH = "android.window.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH";
+ field public static final String PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE = "android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE";
+ field public static final String PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE";
+ field public static final String PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE";
+ field public static final String PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS = "android.window.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS";
+ field public static final String PROPERTY_COMPAT_ENABLE_FAKE_FOCUS = "android.window.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS";
+ field public static final String PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION = "android.window.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION";
}
public static class WindowManager.BadTokenException extends java.lang.RuntimeException {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0a893f05e91c..ce5723b0aa3d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -968,10 +968,6 @@ package android.app {
field public static final int SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY = 11; // 0xb
}
- public static class Notification.MediaStyle extends android.app.Notification.Style {
- method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public android.app.Notification.MediaStyle setRemotePlaybackInfo(@NonNull CharSequence, @DrawableRes int, @Nullable android.app.PendingIntent);
- }
-
public static final class Notification.TvExtender implements android.app.Notification.Extender {
ctor public Notification.TvExtender();
ctor public Notification.TvExtender(android.app.Notification);
@@ -9984,6 +9980,7 @@ package android.net.wifi.sharedconnectivity.app {
public final class HotspotNetwork implements android.os.Parcelable {
method public int describeContents();
method public long getDeviceId();
+ method @NonNull public android.os.Bundle getExtras();
method public int getHostNetworkType();
method @Nullable public String getHotspotBssid();
method @NonNull public java.util.Set<java.lang.Integer> getHotspotSecurityTypes();
@@ -10003,6 +10000,7 @@ package android.net.wifi.sharedconnectivity.app {
method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder addHotspotSecurityType(int);
method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork build();
method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setDeviceId(long);
+ method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setExtras(@NonNull android.os.Bundle);
method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHostNetworkType(int);
method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHotspotBssid(@NonNull String);
method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHotspotSsid(@NonNull String);
@@ -10039,6 +10037,7 @@ package android.net.wifi.sharedconnectivity.app {
public final class KnownNetwork implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public android.os.Bundle getExtras();
method @Nullable public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo getNetworkProviderInfo();
method public int getNetworkSource();
method @NonNull public java.util.Set<java.lang.Integer> getSecurityTypes();
@@ -10054,6 +10053,7 @@ package android.net.wifi.sharedconnectivity.app {
ctor public KnownNetwork.Builder();
method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder addSecurityType(int);
method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork build();
+ method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setExtras(@NonNull android.os.Bundle);
method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setNetworkProviderInfo(@Nullable android.net.wifi.sharedconnectivity.app.NetworkProviderInfo);
method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setNetworkSource(int);
method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setSsid(@NonNull String);
@@ -10085,6 +10085,7 @@ package android.net.wifi.sharedconnectivity.app {
method @IntRange(from=0, to=3) public int getConnectionStrength();
method @NonNull public String getDeviceName();
method public int getDeviceType();
+ method @NonNull public android.os.Bundle getExtras();
method @NonNull public String getModelName();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.NetworkProviderInfo> CREATOR;
@@ -10103,6 +10104,7 @@ package android.net.wifi.sharedconnectivity.app {
method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setConnectionStrength(@IntRange(from=0, to=3) int);
method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setDeviceName(@NonNull String);
method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setDeviceType(int);
+ method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setExtras(@NonNull android.os.Bundle);
method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setModelName(@NonNull String);
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 445b957a44f3..6bfaa352f3f7 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -516,6 +516,10 @@ package android.app {
package android.app.admin {
+ public final class AccountTypePolicyKey extends android.app.admin.PolicyKey {
+ ctor public AccountTypePolicyKey(@NonNull String, @NonNull String);
+ }
+
public final class DeviceAdminAuthority extends android.app.admin.Authority {
field @NonNull public static final android.app.admin.DeviceAdminAuthority DEVICE_ADMIN_AUTHORITY;
}
@@ -612,6 +616,10 @@ package android.app.admin {
field @NonNull public static final android.app.admin.FlagUnion FLAG_UNION;
}
+ public final class IntentFilterPolicyKey extends android.app.admin.PolicyKey {
+ ctor public IntentFilterPolicyKey(@NonNull String, @NonNull android.content.IntentFilter);
+ }
+
public final class MostRecent<V> extends android.app.admin.ResolutionMechanism<V> {
ctor public MostRecent();
method public int describeContents();
@@ -627,6 +635,14 @@ package android.app.admin {
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.MostRestrictive<?>> CREATOR;
}
+ public final class PackagePermissionPolicyKey extends android.app.admin.PolicyKey {
+ ctor public PackagePermissionPolicyKey(@NonNull String, @NonNull String, @NonNull String);
+ }
+
+ public final class PackagePolicyKey extends android.app.admin.PolicyKey {
+ ctor public PackagePolicyKey(@NonNull String, @NonNull String);
+ }
+
public final class PolicyState<V> implements android.os.Parcelable {
method @NonNull public android.app.admin.ResolutionMechanism<V> getResolutionMechanism();
}
@@ -676,6 +692,10 @@ package android.app.admin {
method public int getOperation();
}
+ public final class UserRestrictionPolicyKey extends android.app.admin.PolicyKey {
+ ctor public UserRestrictionPolicyKey(@NonNull String, @NonNull String);
+ }
+
}
package android.app.assist {
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index a81ef18c8022..d0ce70133414 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -69,7 +69,7 @@ public abstract class Animator implements Cloneable {
* backing field for backgroundPauseDelay property. This could be simply a hardcoded
* value in AnimationHandler, but it is useful to be able to change the value in tests.
*/
- private static long sBackgroundPauseDelay = 10000;
+ private static long sBackgroundPauseDelay = 1000;
/**
* Sets the duration for delaying pausing animators when apps go into the background.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2751b54ebdb7..682fec8105d5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5840,26 +5840,6 @@ public final class ActivityThread extends ClientTransactionHandler
r.activity.mChangingConfigurations = true;
- // If we are preserving the main window across relaunches we would also like to preserve
- // the children. However the client side view system does not support preserving
- // the child views so we notify the window manager to expect these windows to
- // be replaced and defer requests to destroy or hide them. This way we can achieve
- // visual continuity. It's important that we do this here prior to pause and destroy
- // as that is when we may hide or remove the child views.
- //
- // There is another scenario, if we have decided locally to relaunch the app from a
- // call to recreate, then none of the windows will be prepared for replacement or
- // preserved by the server, so we want to notify it that we are preparing to replace
- // everything
- try {
- if (r.mPreserveWindow) {
- WindowManagerGlobal.getWindowSession().prepareToReplaceWindows(
- r.token, true /* childrenOnly */);
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e78fb179eb6c..502ef0db586b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4634,9 +4634,9 @@ public class Notification implements Parcelable
* Set whether this is an "ongoing" notification.
*
* Ongoing notifications cannot be dismissed by the user on locked devices, or by
- * notification listeners, and some notifications (device management, media) cannot be
- * dismissed on unlocked devices, so your application or service must take
- * care of canceling them.
+ * notification listeners, and some notifications (call, device management, media) cannot
+ * be dismissed on unlocked devices, so your application or service must take care of
+ * canceling them.
*
* They are typically used to indicate a background task that the user is actively engaged
* with (e.g., playing music) or is pending in some way and therefore occupying the device
@@ -9163,10 +9163,7 @@ public class Notification implements Parcelable
* {@code null}, in which case the output switcher will be disabled.
* This intent should open an Activity or it will be ignored.
* @return MediaStyle
- *
- * @hide
*/
- @SystemApi
@RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL)
@NonNull
public MediaStyle setRemotePlaybackInfo(@NonNull CharSequence deviceName,
diff --git a/core/java/android/app/admin/AccountTypePolicyKey.java b/core/java/android/app/admin/AccountTypePolicyKey.java
index 6417cd47b504..9e376a7e2bee 100644
--- a/core/java/android/app/admin/AccountTypePolicyKey.java
+++ b/core/java/android/app/admin/AccountTypePolicyKey.java
@@ -23,6 +23,7 @@ import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_KEY;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.Parcel;
@@ -49,6 +50,7 @@ public final class AccountTypePolicyKey extends PolicyKey {
/**
* @hide
*/
+ @TestApi
public AccountTypePolicyKey(@NonNull String key, @NonNull String accountType) {
super(key);
mAccountType = Objects.requireNonNull((accountType));
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 024141777604..6bbbfe1ef4b0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -57,6 +57,7 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa
import android.Manifest.permission;
import android.accounts.Account;
+import android.annotation.BroadcastBehavior;
import android.annotation.CallbackExecutor;
import android.annotation.ColorInt;
import android.annotation.IntDef;
@@ -3998,6 +3999,27 @@ public class DevicePolicyManager {
public static final String EXTRA_RESOURCE_IDS =
"android.app.extra.RESOURCE_IDS";
+ /**
+ * Broadcast Action: Broadcast sent to indicate that the device financing state has changed.
+ *
+ * <p>This occurs when, for example, a financing kiosk app has been added or removed.
+ *
+ * <p>To query the current device financing state see {@link #isDeviceFinanced}.
+ *
+ * <p>This will be delivered to the following apps if they include a receiver for this action
+ * in their manifest:
+ * <ul>
+ * <li>Device owner admins.
+ * <li>Organization-owned profile owner admins
+ * <li>The supervision app
+ * <li>The device management role holder
+ * </ul>
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true, includeBackground = true)
+ public static final String ACTION_DEVICE_FINANCING_STATE_CHANGED =
+ "android.app.admin.action.DEVICE_FINANCING_STATE_CHANGED";
+
/** Allow the user to choose whether to enable MTE on the device. */
public static final int MTE_NOT_CONTROLLED_BY_POLICY = 0;
diff --git a/core/java/android/app/admin/IntentFilterPolicyKey.java b/core/java/android/app/admin/IntentFilterPolicyKey.java
index b0af4cd77749..30aad965c008 100644
--- a/core/java/android/app/admin/IntentFilterPolicyKey.java
+++ b/core/java/android/app/admin/IntentFilterPolicyKey.java
@@ -23,6 +23,7 @@ import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_KEY;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Parcel;
@@ -49,6 +50,7 @@ public final class IntentFilterPolicyKey extends PolicyKey {
/**
* @hide
*/
+ @TestApi
public IntentFilterPolicyKey(@NonNull String identifier, @NonNull IntentFilter filter) {
super(identifier);
mFilter = Objects.requireNonNull(filter);
diff --git a/core/java/android/app/admin/PackagePermissionPolicyKey.java b/core/java/android/app/admin/PackagePermissionPolicyKey.java
index 08c4224021f1..7fd514cebd7c 100644
--- a/core/java/android/app/admin/PackagePermissionPolicyKey.java
+++ b/core/java/android/app/admin/PackagePermissionPolicyKey.java
@@ -24,6 +24,7 @@ import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_KEY;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -53,6 +54,7 @@ public final class PackagePermissionPolicyKey extends PolicyKey {
/**
* @hide
*/
+ @TestApi
public PackagePermissionPolicyKey(@NonNull String identifier, @NonNull String packageName,
@NonNull String permissionName) {
super(identifier);
diff --git a/core/java/android/app/admin/PackagePolicyKey.java b/core/java/android/app/admin/PackagePolicyKey.java
index b2a8d5d24b84..2ab00bc3146c 100644
--- a/core/java/android/app/admin/PackagePolicyKey.java
+++ b/core/java/android/app/admin/PackagePolicyKey.java
@@ -23,6 +23,7 @@ import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_KEY;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -50,6 +51,7 @@ public final class PackagePolicyKey extends PolicyKey {
/**
* @hide
*/
+ @TestApi
public PackagePolicyKey(@NonNull String key, @NonNull String packageName) {
super(key);
mPackageName = Objects.requireNonNull((packageName));
diff --git a/core/java/android/app/admin/UserRestrictionPolicyKey.java b/core/java/android/app/admin/UserRestrictionPolicyKey.java
index 880b58b8c321..aeb238041605 100644
--- a/core/java/android/app/admin/UserRestrictionPolicyKey.java
+++ b/core/java/android/app/admin/UserRestrictionPolicyKey.java
@@ -20,6 +20,7 @@ import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_KEY;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.Parcel;
@@ -40,6 +41,7 @@ public final class UserRestrictionPolicyKey extends PolicyKey {
/**
* @hide
*/
+ @TestApi
public UserRestrictionPolicyKey(@NonNull String identifier, @NonNull String restriction) {
super(identifier);
mRestriction = Objects.requireNonNull(restriction);
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index fe10b7f8b3f4..27f6a266597c 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -31,6 +31,7 @@ import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
+import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -311,20 +312,27 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
super.onLayout(changed, left, top, right, bottom);
} catch (final RuntimeException e) {
Log.e(TAG, "Remote provider threw runtime exception, using error view instead.", e);
- removeViewInLayout(mView);
- View child = getErrorView();
- prepareView(child);
- addViewInLayout(child, 0, child.getLayoutParams());
- measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
- child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight,
- child.getMeasuredHeight() + mPaddingTop + mPaddingBottom);
- mView = child;
- mViewMode = VIEW_MODE_ERROR;
+ handleViewError();
}
}
/**
+ * Remove bad view and replace with error message view
+ */
+ private void handleViewError() {
+ removeViewInLayout(mView);
+ View child = getErrorView();
+ prepareView(child);
+ addViewInLayout(child, 0, child.getLayoutParams());
+ measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
+ child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight,
+ child.getMeasuredHeight() + mPaddingTop + mPaddingBottom);
+ mView = child;
+ mViewMode = VIEW_MODE_ERROR;
+ }
+
+ /**
* Provide guidance about the size of this widget to the AppWidgetManager. The widths and
* heights should correspond to the full area the AppWidgetHostView is given. Padding added by
* the framework will be accounted for automatically. This information gets embedded into the
@@ -953,4 +961,15 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
reapplyLastRemoteViews();
}
}
+
+ @Override
+ protected void dispatchDraw(@NonNull Canvas canvas) {
+ try {
+ super.dispatchDraw(canvas);
+ } catch (Exception e) {
+ // Catch draw exceptions that may be caused by RemoteViews
+ Log.e(TAG, "Drawing view failed: " + e);
+ post(this::handleViewError);
+ }
+ }
}
diff --git a/core/java/android/hardware/input/InputDeviceLightsManager.java b/core/java/android/hardware/input/InputDeviceLightsManager.java
index 802e6dde497a..f4ee9a21c42c 100644
--- a/core/java/android/hardware/input/InputDeviceLightsManager.java
+++ b/core/java/android/hardware/input/InputDeviceLightsManager.java
@@ -18,6 +18,7 @@ package android.hardware.input;
import android.annotation.NonNull;
import android.app.ActivityThread;
+import android.content.Context;
import android.hardware.lights.Light;
import android.hardware.lights.LightState;
import android.hardware.lights.LightsManager;
@@ -30,22 +31,22 @@ import java.lang.ref.Reference;
import java.util.List;
/**
- * LightsManager manages an input device's lights {@link android.hardware.input.Light}.
+ * LightsManager manages an input device's lights {@link android.hardware.lights.Light}
*/
class InputDeviceLightsManager extends LightsManager {
private static final String TAG = "InputDeviceLightsManager";
private static final boolean DEBUG = false;
- private final InputManager mInputManager;
+ private final InputManagerGlobal mGlobal;
// The input device ID.
private final int mDeviceId;
// Package name
private final String mPackageName;
- InputDeviceLightsManager(InputManager inputManager, int deviceId) {
- super(ActivityThread.currentActivityThread().getSystemContext());
- mInputManager = inputManager;
+ InputDeviceLightsManager(Context context, int deviceId) {
+ super(context);
+ mGlobal = InputManagerGlobal.getInstance();
mDeviceId = deviceId;
mPackageName = ActivityThread.currentPackageName();
}
@@ -57,7 +58,7 @@ class InputDeviceLightsManager extends LightsManager {
*/
@Override
public @NonNull List<Light> getLights() {
- return mInputManager.getLights(mDeviceId);
+ return mGlobal.getLights(mDeviceId);
}
/**
@@ -68,7 +69,7 @@ class InputDeviceLightsManager extends LightsManager {
@Override
public @NonNull LightState getLightState(@NonNull Light light) {
Preconditions.checkNotNull(light);
- return mInputManager.getLightState(mDeviceId, light);
+ return mGlobal.getLightState(mDeviceId, light);
}
/**
@@ -77,7 +78,7 @@ class InputDeviceLightsManager extends LightsManager {
@Override
public @NonNull LightsSession openSession() {
final LightsSession session = new InputDeviceLightsSession();
- mInputManager.openLightSession(mDeviceId, mPackageName, session.getToken());
+ mGlobal.openLightSession(mDeviceId, mPackageName, session.getToken());
return session;
}
@@ -113,7 +114,7 @@ class InputDeviceLightsManager extends LightsManager {
Preconditions.checkNotNull(request);
Preconditions.checkArgument(!mClosed);
- mInputManager.requestLights(mDeviceId, request, getToken());
+ mGlobal.requestLights(mDeviceId, request, getToken());
}
/**
@@ -122,7 +123,7 @@ class InputDeviceLightsManager extends LightsManager {
@Override
public void close() {
if (!mClosed) {
- mInputManager.closeLightSession(mDeviceId, getToken());
+ mGlobal.closeLightSession(mDeviceId, getToken());
mClosed = true;
mCloseGuard.close();
}
diff --git a/core/java/android/hardware/input/InputDeviceVibrator.java b/core/java/android/hardware/input/InputDeviceVibrator.java
index ce6b52391f12..9c1826071822 100644
--- a/core/java/android/hardware/input/InputDeviceVibrator.java
+++ b/core/java/android/hardware/input/InputDeviceVibrator.java
@@ -45,14 +45,14 @@ final class InputDeviceVibrator extends Vibrator {
private final int mDeviceId;
private final VibratorInfo mVibratorInfo;
private final Binder mToken;
- private final InputManager mInputManager;
+ private final InputManagerGlobal mGlobal;
@GuardedBy("mDelegates")
private final ArrayMap<OnVibratorStateChangedListener,
OnVibratorStateChangedListenerDelegate> mDelegates = new ArrayMap<>();
- InputDeviceVibrator(InputManager inputManager, int deviceId, int vibratorId) {
- mInputManager = inputManager;
+ InputDeviceVibrator(int deviceId, int vibratorId) {
+ mGlobal = InputManagerGlobal.getInstance();
mDeviceId = deviceId;
mVibratorInfo = new VibratorInfo.Builder(vibratorId)
.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
@@ -93,7 +93,7 @@ final class InputDeviceVibrator extends Vibrator {
@Override
public boolean isVibrating() {
- return mInputManager.isVibrating(mDeviceId);
+ return mGlobal.isVibrating(mDeviceId);
}
/**
@@ -132,7 +132,7 @@ final class InputDeviceVibrator extends Vibrator {
final OnVibratorStateChangedListenerDelegate delegate =
new OnVibratorStateChangedListenerDelegate(listener, executor);
- if (!mInputManager.registerVibratorStateListener(mDeviceId, delegate)) {
+ if (!mGlobal.registerVibratorStateListener(mDeviceId, delegate)) {
Log.w(TAG, "Failed to register vibrate state listener");
return;
}
@@ -156,7 +156,7 @@ final class InputDeviceVibrator extends Vibrator {
if (mDelegates.containsKey(listener)) {
final OnVibratorStateChangedListenerDelegate delegate = mDelegates.get(listener);
- if (!mInputManager.unregisterVibratorStateListener(mDeviceId, delegate)) {
+ if (!mGlobal.unregisterVibratorStateListener(mDeviceId, delegate)) {
Log.w(TAG, "Failed to unregister vibrate state listener");
return;
}
@@ -176,12 +176,12 @@ final class InputDeviceVibrator extends Vibrator {
@Override
public void vibrate(int uid, String opPkg, @NonNull VibrationEffect effect, String reason,
@NonNull VibrationAttributes attributes) {
- mInputManager.vibrate(mDeviceId, effect, mToken);
+ mGlobal.vibrate(mDeviceId, effect, mToken);
}
@Override
public void cancel() {
- mInputManager.cancelVibrate(mDeviceId, mToken);
+ mGlobal.cancelVibrate(mDeviceId, mToken);
}
@Override
diff --git a/core/java/android/hardware/input/InputDeviceVibratorManager.java b/core/java/android/hardware/input/InputDeviceVibratorManager.java
index d77f9c351b8e..64b566772884 100644
--- a/core/java/android/hardware/input/InputDeviceVibratorManager.java
+++ b/core/java/android/hardware/input/InputDeviceVibratorManager.java
@@ -40,7 +40,7 @@ public class InputDeviceVibratorManager extends VibratorManager
private static final boolean DEBUG = false;
private final Binder mToken;
- private final InputManager mInputManager;
+ private final InputManagerGlobal mGlobal;
// The input device Id.
private final int mDeviceId;
@@ -48,8 +48,8 @@ public class InputDeviceVibratorManager extends VibratorManager
@GuardedBy("mVibrators")
private final SparseArray<Vibrator> mVibrators = new SparseArray<>();
- public InputDeviceVibratorManager(InputManager inputManager, int deviceId) {
- mInputManager = inputManager;
+ public InputDeviceVibratorManager(int deviceId) {
+ mGlobal = InputManagerGlobal.getInstance();
mDeviceId = deviceId;
mToken = new Binder();
@@ -61,10 +61,10 @@ public class InputDeviceVibratorManager extends VibratorManager
mVibrators.clear();
InputDevice inputDevice = InputDevice.getDevice(mDeviceId);
final int[] vibratorIds =
- mInputManager.getVibratorIds(mDeviceId);
+ mGlobal.getVibratorIds(mDeviceId);
for (int i = 0; i < vibratorIds.length; i++) {
mVibrators.put(vibratorIds[i],
- new InputDeviceVibrator(mInputManager, mDeviceId, vibratorIds[i]));
+ new InputDeviceVibrator(mDeviceId, vibratorIds[i]));
}
}
}
@@ -127,12 +127,12 @@ public class InputDeviceVibratorManager extends VibratorManager
@Override
public void vibrate(int uid, String opPkg, @NonNull CombinedVibration effect,
String reason, @Nullable VibrationAttributes attributes) {
- mInputManager.vibrate(mDeviceId, effect, mToken);
+ mGlobal.vibrate(mDeviceId, effect, mToken);
}
@Override
public void cancel() {
- mInputManager.cancelVibrate(mDeviceId, mToken);
+ mGlobal.cancelVibrate(mDeviceId, mToken);
}
@Override
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 054ae21be14a..5dc3825215c0 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -33,21 +33,15 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.hardware.BatteryState;
import android.hardware.SensorManager;
-import android.hardware.lights.Light;
-import android.hardware.lights.LightState;
import android.hardware.lights.LightsManager;
-import android.hardware.lights.LightsRequest;
import android.os.Binder;
import android.os.Build;
-import android.os.CombinedVibration;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IVibratorStateListener;
import android.os.InputEventInjectionSync;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.VibrationEffect;
import android.os.Vibrator;
import android.os.VibratorManager;
import android.util.Log;
@@ -1380,7 +1374,7 @@ public final class InputManager {
* @hide
*/
public Vibrator getInputDeviceVibrator(int deviceId, int vibratorId) {
- return new InputDeviceVibrator(this, deviceId, vibratorId);
+ return new InputDeviceVibrator(deviceId, vibratorId);
}
/**
@@ -1391,85 +1385,7 @@ public final class InputManager {
*/
@NonNull
public VibratorManager getInputDeviceVibratorManager(int deviceId) {
- return new InputDeviceVibratorManager(InputManager.this, deviceId);
- }
-
- /*
- * Get the list of device vibrators
- * @return The list of vibrators IDs
- */
- int[] getVibratorIds(int deviceId) {
- try {
- return mIm.getVibratorIds(deviceId);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
- /*
- * Perform vibration effect
- */
- void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
- try {
- mIm.vibrate(deviceId, effect, token);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
- /*
- * Perform combined vibration effect
- */
- void vibrate(int deviceId, CombinedVibration effect, IBinder token) {
- try {
- mIm.vibrateCombined(deviceId, effect, token);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
- /*
- * Cancel an ongoing vibration
- */
- void cancelVibrate(int deviceId, IBinder token) {
- try {
- mIm.cancelVibrate(deviceId, token);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
- /*
- * Check if input device is vibrating
- */
- boolean isVibrating(int deviceId) {
- try {
- return mIm.isVibrating(deviceId);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
- /**
- * Register input device vibrator state listener
- */
- boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
- try {
- return mIm.registerVibratorStateListener(deviceId, listener);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
- /**
- * Unregister input device vibrator state listener
- */
- boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
- try {
- return mIm.unregisterVibratorStateListener(deviceId, listener);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ return new InputDeviceVibratorManager(deviceId);
}
/**
@@ -1499,77 +1415,7 @@ public final class InputManager {
*/
@NonNull
public LightsManager getInputDeviceLightsManager(int deviceId) {
- return new InputDeviceLightsManager(InputManager.this, deviceId);
- }
-
- /**
- * Gets a list of light objects associated with an input device.
- * @return The list of lights, never null.
- */
- @NonNull List<Light> getLights(int deviceId) {
- try {
- return mIm.getLights(deviceId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns the state of an input device light.
- * @return the light state
- */
- @NonNull LightState getLightState(int deviceId, @NonNull Light light) {
- try {
- return mIm.getLightState(deviceId, light.getId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Request to modify the states of multiple lights.
- *
- * @param request the settings for lights that should change
- */
- void requestLights(int deviceId, @NonNull LightsRequest request, IBinder token) {
- try {
- List<Integer> lightIdList = request.getLights();
- int[] lightIds = new int[lightIdList.size()];
- for (int i = 0; i < lightIds.length; i++) {
- lightIds[i] = lightIdList.get(i);
- }
- List<LightState> lightStateList = request.getLightStates();
- mIm.setLightStates(deviceId, lightIds,
- lightStateList.toArray(new LightState[0]),
- token);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Open light session for input device manager
- *
- * @param token The token for the light session
- */
- void openLightSession(int deviceId, String opPkg, @NonNull IBinder token) {
- try {
- mIm.openLightSession(deviceId, opPkg, token);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Close light session
- *
- */
- void closeLightSession(int deviceId, @NonNull IBinder token) {
- try {
- mIm.closeLightSession(deviceId, token);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return new InputDeviceLightsManager(getContext(), deviceId);
}
/**
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 524d8206bddf..08d81bd3c325 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -27,12 +27,18 @@ import android.hardware.input.InputManager.InputDeviceBatteryListener;
import android.hardware.input.InputManager.InputDeviceListener;
import android.hardware.input.InputManager.KeyboardBacklightListener;
import android.hardware.input.InputManager.OnTabletModeChangedListener;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
+import android.hardware.lights.LightsRequest;
+import android.os.CombinedVibration;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IVibratorStateListener;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.VibrationEffect;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
@@ -903,4 +909,152 @@ public final class InputManagerGlobal {
throw ex.rethrowFromSystemServer();
}
}
+
+ /**
+ * Gets a list of light objects associated with an input device.
+ * @return The list of lights, never null.
+ */
+ @NonNull List<Light> getLights(int deviceId) {
+ try {
+ return mIm.getLights(deviceId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the state of an input device light.
+ * @return the light state
+ */
+ @NonNull LightState getLightState(int deviceId, @NonNull Light light) {
+ try {
+ return mIm.getLightState(deviceId, light.getId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Request to modify the states of multiple lights.
+ *
+ * @param request the settings for lights that should change
+ */
+ void requestLights(int deviceId, @NonNull LightsRequest request, IBinder token) {
+ try {
+ List<Integer> lightIdList = request.getLights();
+ int[] lightIds = new int[lightIdList.size()];
+ for (int i = 0; i < lightIds.length; i++) {
+ lightIds[i] = lightIdList.get(i);
+ }
+ List<LightState> lightStateList = request.getLightStates();
+ mIm.setLightStates(deviceId, lightIds,
+ lightStateList.toArray(new LightState[0]),
+ token);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Open light session for input device manager
+ *
+ * @param token The token for the light session
+ */
+ void openLightSession(int deviceId, String opPkg, @NonNull IBinder token) {
+ try {
+ mIm.openLightSession(deviceId, opPkg, token);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Close light session
+ *
+ */
+ void closeLightSession(int deviceId, @NonNull IBinder token) {
+ try {
+ mIm.closeLightSession(deviceId, token);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /*
+ * Get the list of device vibrators
+ * @return The list of vibrators IDs
+ */
+ int[] getVibratorIds(int deviceId) {
+ try {
+ return mIm.getVibratorIds(deviceId);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /*
+ * Perform vibration effect
+ */
+ void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
+ try {
+ mIm.vibrate(deviceId, effect, token);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /*
+ * Perform combined vibration effect
+ */
+ void vibrate(int deviceId, CombinedVibration effect, IBinder token) {
+ try {
+ mIm.vibrateCombined(deviceId, effect, token);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /*
+ * Cancel an ongoing vibration
+ */
+ void cancelVibrate(int deviceId, IBinder token) {
+ try {
+ mIm.cancelVibrate(deviceId, token);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /*
+ * Check if input device is vibrating
+ */
+ boolean isVibrating(int deviceId) {
+ try {
+ return mIm.isVibrating(deviceId);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Register input device vibrator state listener
+ */
+ boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
+ try {
+ return mIm.registerVibratorStateListener(deviceId, listener);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregister input device vibrator state listener
+ */
+ boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
+ try {
+ return mIm.unregisterVibratorStateListener(deviceId, listener);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 127c7a0476f6..05b6da4f7cbe 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11433,21 +11433,46 @@ public final class Settings {
public @interface DeviceStateRotationLockSetting {
}
+ /** @hide */
+ public static final int DEVICE_STATE_ROTATION_KEY_UNKNOWN = -1;
+ /** @hide */
+ public static final int DEVICE_STATE_ROTATION_KEY_FOLDED = 0;
+ /** @hide */
+ public static final int DEVICE_STATE_ROTATION_KEY_HALF_FOLDED = 1;
+ /** @hide */
+ public static final int DEVICE_STATE_ROTATION_KEY_UNFOLDED = 2;
+
+ /**
+ * The different postures that can be used as keys with
+ * {@link #DEVICE_STATE_ROTATION_LOCK}.
+ * @hide
+ */
+ @IntDef(prefix = {"DEVICE_STATE_ROTATION_KEY_"}, value = {
+ DEVICE_STATE_ROTATION_KEY_UNKNOWN,
+ DEVICE_STATE_ROTATION_KEY_FOLDED,
+ DEVICE_STATE_ROTATION_KEY_HALF_FOLDED,
+ DEVICE_STATE_ROTATION_KEY_UNFOLDED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DeviceStateRotationLockKey {
+ }
+
/**
* Rotation lock setting keyed on device state.
*
- * This holds a serialized map using int keys that represent Device States and value of
+ * This holds a serialized map using int keys that represent postures in
+ * {@link DeviceStateRotationLockKey} and value of
* {@link DeviceStateRotationLockSetting} representing the rotation lock setting for that
- * device state.
+ * posture.
*
* Serialized as key0:value0:key1:value1:...:keyN:valueN.
*
* Example: "0:1:1:2:2:1"
* This example represents a map of:
* <ul>
- * <li>0 -> DEVICE_STATE_ROTATION_LOCK_LOCKED</li>
- * <li>1 -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED</li>
- * <li>2 -> DEVICE_STATE_ROTATION_LOCK_IGNORED</li>
+ * <li>DEVICE_STATE_ROTATION_KEY_FOLDED -> DEVICE_STATE_ROTATION_LOCK_LOCKED</li>
+ * <li>DEVICE_STATE_ROTATION_KEY_HALF_FOLDED -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED</li>
+ * <li>DEVICE_STATE_ROTATION_KEY_UNFOLDED -> DEVICE_STATE_ROTATION_LOCK_IGNORED</li>
* </ul>
*
* @hide
diff --git a/core/java/android/security/net/config/SystemCertificateSource.java b/core/java/android/security/net/config/SystemCertificateSource.java
index 13f7e5d4232b..3a254c1d92fc 100644
--- a/core/java/android/security/net/config/SystemCertificateSource.java
+++ b/core/java/android/security/net/config/SystemCertificateSource.java
@@ -39,9 +39,13 @@ public final class SystemCertificateSource extends DirectoryCertificateSource {
}
private static File getDirectory() {
- // TODO(miguelaranda): figure out correct code path.
+ if ((System.getProperty("system.certs.enabled") != null)
+ && (System.getProperty("system.certs.enabled")).equals("true")) {
+ return new File(System.getenv("ANDROID_ROOT") + "/etc/security/cacerts");
+ }
File updatable_dir = new File("/apex/com.android.conscrypt/cacerts");
- if (updatable_dir.exists() && !(updatable_dir.list().length == 0)) {
+ if (updatable_dir.exists()
+ && !(updatable_dir.list().length == 0)) {
return updatable_dir;
}
return new File(System.getenv("ANDROID_ROOT") + "/etc/security/cacerts");
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 5810642402a3..83de2a0fafbe 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -110,16 +110,6 @@ interface IWindowSession {
int requestedWidth, int requestedHeight, int viewVisibility, int flags, int seq,
int lastSyncSeqId);
- /*
- * Notify the window manager that an application is relaunching and
- * windows should be prepared for replacement.
- *
- * @param appToken The application
- * @param childrenOnly Whether to only prepare child windows for replacement
- * (for example when main windows are being reused via preservation).
- */
- oneway void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly);
-
/**
* Called by a client to report that it ran out of graphics memory.
*/
@@ -304,7 +294,7 @@ interface IWindowSession {
* an input channel where the client can receive input.
*/
void grantInputChannel(int displayId, in SurfaceControl surface, in IWindow window,
- in IBinder hostInputToken, int flags, int privateFlags, int type,
+ in IBinder hostInputToken, int flags, int privateFlags, int inputFeatures, int type,
in IBinder windowToken, in IBinder focusGrantToken, String inputHandleName,
out InputChannel outInputChannel);
@@ -312,7 +302,8 @@ interface IWindowSession {
* Update the flags on an input channel associated with a particular surface.
*/
oneway void updateInputChannel(in IBinder channelToken, int displayId,
- in SurfaceControl surface, int flags, int privateFlags, in Region region);
+ in SurfaceControl surface, int flags, int privateFlags, int inputFeatures,
+ in Region region);
/**
* Transfer window focus to an embedded window if the calling window has focus.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 35ed88fc420e..cda1f3adb9a4 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -863,10 +863,8 @@ public interface WindowManager extends ViewManager {
* android:value="true|false"/&gt;
* &lt;/application&gt;
* </pre>
- *
- * @hide
*/
- // TODO(b/263984287): Make this public API.
+ // TODO(b/263984287): Add CTS tests.
String PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION =
"android.window.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION";
@@ -899,8 +897,6 @@ public interface WindowManager extends ViewManager {
* android:value="false"/&gt;
* &lt;/application&gt;
* </pre>
- *
- * @hide
*/
// TODO(b/263984287): Make this public API.
String PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS =
@@ -937,10 +933,8 @@ public interface WindowManager extends ViewManager {
* android:value="true|false"/&gt;
* &lt;/application&gt;
* </pre>
- *
- * @hide
*/
- // TODO(b/263984287): Make this public API.
+ // TODO(b/263984287): Add CTS tests.
String PROPERTY_COMPAT_ENABLE_FAKE_FOCUS = "android.window.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS";
/**
@@ -976,10 +970,8 @@ public interface WindowManager extends ViewManager {
* android:value="true|false"/&gt;
* &lt;/application&gt;
* </pre>
- *
- * @hide
*/
- // TODO(b/263984287): Make this public API.
+ // TODO(b/263984287): Add CTS tests.
String PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION =
"android.window.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION";
@@ -1023,10 +1015,8 @@ public interface WindowManager extends ViewManager {
* android:value="true|false"/&gt;
* &lt;/application&gt;
* </pre>
- *
- * @hide
*/
- // TODO(b/263984287): Make this public API.
+ // TODO(b/263984287): Add CTS tests.
String PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH =
"android.window.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH";
@@ -1073,17 +1063,28 @@ public interface WindowManager extends ViewManager {
* android:value="true|false"/&gt;
* &lt;/application&gt;
* </pre>
- *
- * @hide
*/
- // TODO(b/263984287): Make this public API.
+ // TODO(b/263984287): Add CTS tests.
String PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE =
"android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE";
/**
* Application level {@link android.content.pm.PackageManager.Property PackageManager
* .Property} for an app to inform the system that the app should be excluded from the
- * compatibility override for orientation set by the device manufacturer.
+ * compatibility override for orientation set by the device manufacturer. When the orientation
+ * override is applied it can:
+ * <ul>
+ * <li>Replace the specific orientation requested by the app with another selected by the
+ device manufacturer, e.g. replace undefined requested by the app with portrait.
+ * <li>Always use an orientation selected by the device manufacturer.
+ * <li>Do one of the above but only when camera connection is open.
+ * </ul>
+ *
+ * <p>This property is different from {@link PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION}
+ * (which is used to avoid orientation loops caused by the incorrect use of {@link
+ * android.app.Activity#setRequestedOrientation}) because this property overrides the app to an
+ * orientation selected by the device manufacturer rather than ignoring one of orientation
+ * requests coming from the app while respecting the previous one.
*
* <p>With this property set to {@code true} or unset, device manufacturers can override
* orientation for the app using their discretion to improve display compatibility.
@@ -1099,10 +1100,8 @@ public interface WindowManager extends ViewManager {
* android:value="true|false"/&gt;
* &lt;/application&gt;
* </pre>
- *
- * @hide
*/
- // TODO(b/263984287): Make this public API.
+ // TODO(b/263984287): Add CTS tests.
String PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE =
"android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE";
@@ -1144,10 +1143,8 @@ public interface WindowManager extends ViewManager {
* android:value="true|false"/&gt;
* &lt;/application&gt;
* </pre>
- *
- * @hide
*/
- // TODO(b/263984287): Make this public API.
+ // TODO(b/263984287): Add CTS tests.
String PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE =
"android.window.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE";
@@ -2815,7 +2812,7 @@ public interface WindowManager extends ViewManager {
*
* @hide
*/
- public static final int PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED = 0x00000002;
+ public static final int PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED = 1 << 1;
/**
* By default, wallpapers are sent new offsets when the wallpaper is scrolled. Wallpapers
@@ -2826,7 +2823,7 @@ public interface WindowManager extends ViewManager {
*
* @hide
*/
- public static final int PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS = 0x00000004;
+ public static final int PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS = 1 << 2;
/**
* When set {@link LayoutParams#TYPE_APPLICATION_OVERLAY} windows will stay visible, even if
@@ -2835,7 +2832,7 @@ public interface WindowManager extends ViewManager {
* @hide
*/
@RequiresPermission(permission.SYSTEM_APPLICATION_OVERLAY)
- public static final int PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY = 0x00000008;
+ public static final int PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY = 1 << 3;
/** In a multiuser system if this flag is set and the owner is a system process then this
* window will appear on all user screens. This overrides the default behavior of window
@@ -2845,7 +2842,7 @@ public interface WindowManager extends ViewManager {
* {@hide} */
@SystemApi
@RequiresPermission(permission.INTERNAL_SYSTEM_WINDOW)
- public static final int SYSTEM_FLAG_SHOW_FOR_ALL_USERS = 0x00000010;
+ public static final int SYSTEM_FLAG_SHOW_FOR_ALL_USERS = 1 << 4;
/**
* Flag to allow this window to have unrestricted gesture exclusion.
@@ -2853,7 +2850,7 @@ public interface WindowManager extends ViewManager {
* @see View#setSystemGestureExclusionRects(List)
* @hide
*/
- public static final int PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION = 0x00000020;
+ public static final int PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION = 1 << 5;
/**
* Never animate position changes of the window.
@@ -2862,20 +2859,20 @@ public interface WindowManager extends ViewManager {
* {@hide}
*/
@UnsupportedAppUsage
- public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 0x00000040;
+ public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 1 << 6;
/** Window flag: special flag to limit the size of the window to be
* original size ([320x480] x density). Used to create window for applications
* running under compatibility mode.
*
* {@hide} */
- public static final int PRIVATE_FLAG_COMPATIBLE_WINDOW = 0x00000080;
+ public static final int PRIVATE_FLAG_COMPATIBLE_WINDOW = 1 << 7;
/** Window flag: a special option intended for system dialogs. When
* this flag is set, the window will demand focus unconditionally when
* it is created.
* {@hide} */
- public static final int PRIVATE_FLAG_SYSTEM_ERROR = 0x00000100;
+ public static final int PRIVATE_FLAG_SYSTEM_ERROR = 1 << 8;
/**
* Flag to indicate that the view hierarchy of the window can only be measured when
@@ -2884,14 +2881,14 @@ public interface WindowManager extends ViewManager {
* views. This reduces the chances to perform measure.
* {@hide}
*/
- public static final int PRIVATE_FLAG_OPTIMIZE_MEASURE = 0x00000200;
+ public static final int PRIVATE_FLAG_OPTIMIZE_MEASURE = 1 << 9;
/**
* Flag that prevents the wallpaper behind the current window from receiving touch events.
*
* {@hide}
*/
- public static final int PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS = 0x00000800;
+ public static final int PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS = 1 << 10;
/**
* Flag to force the status bar window to be visible all the time. If the bar is hidden when
@@ -2900,7 +2897,7 @@ public interface WindowManager extends ViewManager {
*
* {@hide}
*/
- public static final int PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR = 0x00001000;
+ public static final int PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR = 1 << 11;
/**
* Flag to indicate that the window frame should be the requested frame adding the display
@@ -2910,7 +2907,7 @@ public interface WindowManager extends ViewManager {
*
* {@hide}
*/
- public static final int PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT = 0x00002000;
+ public static final int PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT = 1 << 12;
/**
* Flag that will make window ignore app visibility and instead depend purely on the decor
@@ -2918,39 +2915,28 @@ public interface WindowManager extends ViewManager {
* drawing after it launches an app.
* @hide
*/
- public static final int PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY = 0x00004000;
-
- /**
- * Flag to indicate that this window is not expected to be replaced across
- * configuration change triggered activity relaunches. In general the WindowManager
- * expects Windows to be replaced after relaunch, and thus it will preserve their surfaces
- * until the replacement is ready to show in order to prevent visual glitch. However
- * some windows, such as PopupWindows expect to be cleared across configuration change,
- * and thus should hint to the WindowManager that it should not wait for a replacement.
- * @hide
- */
- public static final int PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH = 0x00008000;
+ public static final int PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY = 1 << 13;
/**
* Flag to indicate that this child window should always be laid-out in the parent
* frame regardless of the current windowing mode configuration.
* @hide
*/
- public static final int PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME = 0x00010000;
+ public static final int PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME = 1 << 14;
/**
* Flag to indicate that this window is always drawing the status bar background, no matter
* what the other flags are.
* @hide
*/
- public static final int PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS = 0x00020000;
+ public static final int PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS = 1 << 15;
/**
* Flag to indicate that this window needs Sustained Performance Mode if
* the device supports it.
* @hide
*/
- public static final int PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE = 0x00040000;
+ public static final int PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE = 1 << 16;
/**
* Flag to indicate that any window added by an application process that is of type
@@ -2961,7 +2947,7 @@ public interface WindowManager extends ViewManager {
*/
@SystemApi
@RequiresPermission(permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
- public static final int SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000;
+ public static final int SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 1 << 19;
/**
* Indicates that this window is the rounded corners overlay present on some
@@ -2969,7 +2955,7 @@ public interface WindowManager extends ViewManager {
* screen magnification, and mirroring.
* @hide
*/
- public static final int PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY = 0x00100000;
+ public static final int PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY = 1 << 20;
/**
* Flag to indicate that this window will be excluded while computing the magnifiable region
@@ -2983,7 +2969,7 @@ public interface WindowManager extends ViewManager {
* </p><p>
* @hide
*/
- public static final int PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION = 0x00200000;
+ public static final int PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION = 1 << 21;
/**
* Flag to prevent the window from being magnified by the accessibility magnifier.
@@ -2991,7 +2977,7 @@ public interface WindowManager extends ViewManager {
* TODO(b/190623172): This is a temporary solution and need to find out another way instead.
* @hide
*/
- public static final int PRIVATE_FLAG_NOT_MAGNIFIABLE = 0x00400000;
+ public static final int PRIVATE_FLAG_NOT_MAGNIFIABLE = 1 << 22;
/**
* Flag to indicate that the status bar window is in a state such that it forces showing
@@ -3000,54 +2986,54 @@ public interface WindowManager extends ViewManager {
* It only takes effects if this is set by {@link LayoutParams#TYPE_STATUS_BAR}.
* @hide
*/
- public static final int PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION = 0x00800000;
+ public static final int PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION = 1 << 23;
/**
* Flag to indicate that the window is color space agnostic, and the color can be
* interpreted to any color space.
* @hide
*/
- public static final int PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC = 0x01000000;
+ public static final int PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC = 1 << 24;
/**
* Flag to request creation of a BLAST (Buffer as LayerState) Layer.
* If not specified the client will receive a BufferQueue layer.
* @hide
*/
- public static final int PRIVATE_FLAG_USE_BLAST = 0x02000000;
+ public static final int PRIVATE_FLAG_USE_BLAST = 1 << 25;
/**
* Flag to indicate that the window is controlling the appearance of system bars. So we
* don't need to adjust it by reading its system UI flags for compatibility.
* @hide
*/
- public static final int PRIVATE_FLAG_APPEARANCE_CONTROLLED = 0x04000000;
+ public static final int PRIVATE_FLAG_APPEARANCE_CONTROLLED = 1 << 26;
/**
* Flag to indicate that the window is controlling the behavior of system bars. So we don't
* need to adjust it by reading its window flags or system UI flags for compatibility.
* @hide
*/
- public static final int PRIVATE_FLAG_BEHAVIOR_CONTROLLED = 0x08000000;
+ public static final int PRIVATE_FLAG_BEHAVIOR_CONTROLLED = 1 << 27;
/**
* Flag to indicate that the window is controlling how it fits window insets on its own.
* So we don't need to adjust its attributes for fitting window insets.
* @hide
*/
- public static final int PRIVATE_FLAG_FIT_INSETS_CONTROLLED = 0x10000000;
+ public static final int PRIVATE_FLAG_FIT_INSETS_CONTROLLED = 1 << 28;
/**
* Flag to indicate that the window is a trusted overlay.
* @hide
*/
- public static final int PRIVATE_FLAG_TRUSTED_OVERLAY = 0x20000000;
+ public static final int PRIVATE_FLAG_TRUSTED_OVERLAY = 1 << 29;
/**
* Flag to indicate that the parent frame of a window should be inset by IME.
* @hide
*/
- public static final int PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME = 0x40000000;
+ public static final int PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME = 1 << 30;
/**
* Flag to indicate that we want to intercept and handle global drag and drop for all users.
@@ -3062,7 +3048,7 @@ public interface WindowManager extends ViewManager {
* @hide
*/
@RequiresPermission(permission.MANAGE_ACTIVITY_TASKS)
- public static final int PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP = 0x80000000;
+ public static final int PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP = 1 << 31;
/**
* An internal annotation for flags that can be specified to {@link #softInputMode}.
@@ -3093,7 +3079,6 @@ public interface WindowManager extends ViewManager {
PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR,
PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT,
PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY,
- PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH,
PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME,
PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS,
PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE,
@@ -3169,10 +3154,6 @@ public interface WindowManager extends ViewManager {
equals = PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY,
name = "FORCE_DECOR_VIEW_VISIBILITY"),
@ViewDebug.FlagToString(
- mask = PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH,
- equals = PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH,
- name = "WILL_NOT_REPLACE_ON_RELAUNCH"),
- @ViewDebug.FlagToString(
mask = PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME,
equals = PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME,
name = "LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME"),
@@ -3635,9 +3616,20 @@ public interface WindowManager extends ViewManager {
/**
* The preferred refresh rate for the window.
* <p>
- * This must be one of the supported refresh rates obtained for the display(s) the window
- * is on. The selected refresh rate will be applied to the display's default mode.
+ * Before API 34, this must be one of the supported refresh rates obtained
+ * for the display(s) the window is on. The selected refresh rate will be
+ * applied to the display's default mode.
+ * <p>
+ * Starting API 34, this value is not limited to the supported refresh rates
+ * obtained from the display(s) for the window: it can be any refresh rate
+ * the window intends to run at. Any refresh rate can be provided as the
+ * preferred window refresh rate. The OS will select the refresh rate that
+ * best matches the {@link #preferredRefreshRate}.
* <p>
+ * Setting this value is the equivalent of calling {@link Surface#setFrameRate} with (
+ * preferred_frame_rate,
+ * {@link Surface#FRAME_RATE_COMPATIBILITY_DEFAULT},
+ * {@link Surface#CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS}).
* This should be used in favor of {@link LayoutParams#preferredDisplayModeId} for
* applications that want to specify the refresh rate, but do not want to specify a
* preference for any other displayMode properties (e.g., resolution).
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index b157ea0c641f..0560cafe3e52 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -139,7 +139,7 @@ public class WindowlessWindowManager implements IWindowSession {
try {
mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId,
state.mSurfaceControl, state.mParams.flags, state.mParams.privateFlags,
- state.mInputRegion);
+ state.mParams.inputFeatures, state.mInputRegion);
} catch (RemoteException e) {
Log.e(TAG, "Failed to update surface input channel: ", e);
}
@@ -189,12 +189,13 @@ public class WindowlessWindowManager implements IWindowSession {
mRealWm.grantInputChannel(displayId,
new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"),
window, mHostInputToken,
- attrs.flags, attrs.privateFlags, attrs.type, attrs.token,
- mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);
+ attrs.flags, attrs.privateFlags, attrs.inputFeatures, attrs.type,
+ attrs.token, mFocusGrantToken, attrs.getTitle().toString(),
+ outInputChannel);
} else {
mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags,
- attrs.privateFlags, attrs.type, attrs.token, mFocusGrantToken,
- attrs.getTitle().toString(), outInputChannel);
+ attrs.privateFlags, attrs.inputFeatures, attrs.type, attrs.token,
+ mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to grant input to surface: ", e);
@@ -381,16 +382,19 @@ public class WindowlessWindowManager implements IWindowSession {
outMergedConfiguration.setConfiguration(mConfiguration, mConfiguration);
}
- if ((attrChanges & WindowManager.LayoutParams.FLAGS_CHANGED) != 0
- && state.mInputChannelToken != null) {
+ final int inputChangeMask = WindowManager.LayoutParams.FLAGS_CHANGED
+ | WindowManager.LayoutParams.INPUT_FEATURES_CHANGED;
+ if ((attrChanges & inputChangeMask) != 0 && state.mInputChannelToken != null) {
try {
- if(mRealWm instanceof IWindowSession.Stub) {
+ if (mRealWm instanceof IWindowSession.Stub) {
mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId,
new SurfaceControl(sc, "WindowlessWindowManager.relayout"),
- attrs.flags, attrs.privateFlags, state.mInputRegion);
+ attrs.flags, attrs.privateFlags, attrs.inputFeatures,
+ state.mInputRegion);
} else {
mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, sc,
- attrs.flags, attrs.privateFlags, state.mInputRegion);
+ attrs.flags, attrs.privateFlags, attrs.inputFeatures,
+ state.mInputRegion);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to update surface input channel: ", e);
@@ -415,10 +419,6 @@ public class WindowlessWindowManager implements IWindowSession {
}
@Override
- public void prepareToReplaceWindows(android.os.IBinder appToken, boolean childrenOnly) {
- }
-
- @Override
public boolean outOfMemory(android.view.IWindow window) {
return false;
}
@@ -564,14 +564,14 @@ public class WindowlessWindowManager implements IWindowSession {
@Override
public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window,
- IBinder hostInputToken, int flags, int privateFlags, int type,
+ IBinder hostInputToken, int flags, int privateFlags, int inputFeatures, int type,
IBinder windowToken, IBinder focusGrantToken, String inputHandleName,
InputChannel outInputChannel) {
}
@Override
public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
- int flags, int privateFlags, Region region) {
+ int flags, int privateFlags, int inputFeatures, Region region) {
}
@Override
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index c1ec168af145..d54addbbcb8d 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -19,7 +19,6 @@ package android.widget;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1644,8 +1643,7 @@ public class PopupWindow {
p.width = mLastWidth = mWidth;
}
- p.privateFlags = PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH
- | PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
+ p.privateFlags = PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
// Used for debugging.
p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index ca57c84a1631..fceee4e01799 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -189,6 +189,9 @@ public class Toast {
/**
* Show the view for the specified duration.
+ *
+ * <p>Note that toasts being sent from the background are rate limited, so avoid sending such
+ * toasts in quick succession.
*/
public void show() {
if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 70a1354e3046..06e91c3bebfa 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -824,6 +824,9 @@
<protected-broadcast android:name="android.companion.virtual.action.VIRTUAL_DEVICE_REMOVED" />
<protected-broadcast android:name="com.android.internal.intent.action.FLASH_NOTIFICATION_START_PREVIEW" />
<protected-broadcast android:name="com.android.internal.intent.action.FLASH_NOTIFICATION_STOP_PREVIEW" />
+ <protected-broadcast android:name="android.app.admin.action.DEVICE_FINANCING_STATE_CHANGED" />
+ <protected-broadcast android:name="android.app.admin.action.DEVICE_POLICY_SET_RESULT" />
+ <protected-broadcast android:name="android.app.admin.action.DEVICE_POLICY_CHANGED" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2ed181771cb7..220a1935f51a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -720,14 +720,13 @@
display is powered on at the same time. -->
<bool name="config_supportsConcurrentInternalDisplays">true</bool>
- <!-- Map of DeviceState to rotation lock setting. Each entry must be in the format
- "key:value", for example: "0:1".
- The keys are device states, and the values are one of
- Settings.Secure.DeviceStateRotationLockSetting.
- Any device state that doesn't have a default set here will be treated as
- DEVICE_STATE_ROTATION_LOCK_IGNORED meaning it will not have its own rotation lock setting.
- If this map is missing, the feature is disabled and only one global rotation lock setting
- will apply, regardless of device state. -->
+ <!-- Map of device posture to rotation lock setting. Each entry must be in the format
+ "key:value", or "key:value:fallback_key" for example: "0:1" or "2:0:1". The keys are one of
+ Settings.Secure.DeviceStateRotationLockKey, and the values are one of
+ Settings.Secure.DeviceStateRotationLockSetting.
+ The fallback is a key to a device posture that can be specified when the value is
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED.
+ -->
<string-array name="config_perDeviceStateRotationLockDefaults" />
<!-- Dock behavior -->
diff --git a/core/tests/coretests/src/android/view/inputmethod/DeleteRangeGestureTest.java b/core/tests/coretests/src/android/view/inputmethod/DeleteRangeGestureTest.java
new file mode 100644
index 000000000000..d7b911dda672
--- /dev/null
+++ b/core/tests/coretests/src/android/view/inputmethod/DeleteRangeGestureTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package android.view.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.graphics.RectF;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@ApiTest(apis = {"android.view.inputmethod.DeleteRangeGesture.Builder#setGranularity",
+ "android.view.inputmethod.DeleteRangeGesture.Builder#setDeletionStartArea",
+ "android.view.inputmethod.DeleteRangeGesture.Builder#setDeletionEndArea",
+ "android.view.inputmethod.DeleteRangeGesture.Builder#setFallbackText",
+ "android.view.inputmethod.DeleteRangeGesture.Builder#build"})
+public class DeleteRangeGestureTest {
+ private static final RectF DELETION_START_RECTANGLE = new RectF(1, 2, 3, 4);
+ private static final RectF DELETION_END_RECTANGLE = new RectF(0, 2, 3, 4);
+ private static final String FALLBACK_TEXT = "fallback_test";
+
+ @Test
+ public void testBuilder() {
+ DeleteRangeGesture.Builder builder = new DeleteRangeGesture.Builder();
+ DeleteRangeGesture gesture = builder.setGranularity(HandwritingGesture.GRANULARITY_WORD)
+ .setDeletionStartArea(DELETION_START_RECTANGLE)
+ .setDeletionEndArea(DELETION_END_RECTANGLE)
+ .setFallbackText(FALLBACK_TEXT).build();
+ assertNotNull(gesture);
+ assertEquals(HandwritingGesture.GRANULARITY_WORD, gesture.getGranularity());
+ assertEquals(DELETION_START_RECTANGLE, gesture.getDeletionStartArea());
+ assertEquals(DELETION_END_RECTANGLE, gesture.getDeletionEndArea());
+ assertEquals(FALLBACK_TEXT, gesture.getFallbackText());
+ }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/InsertGestureTest.java b/core/tests/coretests/src/android/view/inputmethod/InsertGestureTest.java
new file mode 100644
index 000000000000..47a724d36038
--- /dev/null
+++ b/core/tests/coretests/src/android/view/inputmethod/InsertGestureTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package android.view.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.graphics.PointF;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@ApiTest(apis = {"android.view.inputmethod.InsertGesture.Builder#setInsertionPoint",
+ "android.view.inputmethod.InsertGesture.Builder#setTextToInsert",
+ "android.view.inputmethod.InsertGesture.Builder#setFallbackText",
+ "android.view.inputmethod.InsertGesture.Builder#build"})
+public class InsertGestureTest {
+ private static final PointF INSERTION_POINT = new PointF(1, 2);
+ private static final String FALLBACK_TEXT = "fallback_text";
+ private static final String TEXT_TO_INSERT = "text";
+
+ @Test
+ public void testBuilder() {
+ InsertGesture.Builder builder = new InsertGesture.Builder();
+ InsertGesture gesture = builder.setInsertionPoint(INSERTION_POINT)
+ .setTextToInsert(TEXT_TO_INSERT)
+ .setFallbackText(FALLBACK_TEXT).build();
+ assertNotNull(gesture);
+ assertEquals(INSERTION_POINT, gesture.getInsertionPoint());
+ assertEquals(FALLBACK_TEXT, gesture.getFallbackText());
+ assertEquals(TEXT_TO_INSERT, gesture.getTextToInsert());
+ }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/InsertModeGestureTest.java b/core/tests/coretests/src/android/view/inputmethod/InsertModeGestureTest.java
new file mode 100644
index 000000000000..11ddba110f7a
--- /dev/null
+++ b/core/tests/coretests/src/android/view/inputmethod/InsertModeGestureTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+package android.view.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.graphics.PointF;
+import android.os.CancellationSignal;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@ApiTest(apis = {"android.view.inputmethod.InsertModeGesture.Builder#setInsertionPoint",
+ "android.view.inputmethod.InsertModeGesture.Builder#setCancellationSignal",
+ "android.view.inputmethod.InsertModeGesture.Builder#setFallbackText",
+ "android.view.inputmethod.InsertModeGesture.Builder#build"})
+public class InsertModeGestureTest {
+ private static final PointF INSERTION_POINT = new PointF(1, 2);
+ private static final String FALLBACK_TEXT = "fallback_text";
+ private static final CancellationSignal CANCELLATION_SIGNAL = new CancellationSignal();
+
+ @Test
+ public void testBuilder() {
+ InsertModeGesture.Builder builder = new InsertModeGesture.Builder();
+ InsertModeGesture gesture = builder.setInsertionPoint(INSERTION_POINT)
+ .setCancellationSignal(CANCELLATION_SIGNAL)
+ .setFallbackText(FALLBACK_TEXT).build();
+ assertNotNull(gesture);
+ assertEquals(INSERTION_POINT, gesture.getInsertionPoint());
+ assertEquals(FALLBACK_TEXT, gesture.getFallbackText());
+ assertEquals(CANCELLATION_SIGNAL, gesture.getCancellationSignal());
+ }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/SelectGestureTest.java b/core/tests/coretests/src/android/view/inputmethod/SelectGestureTest.java
new file mode 100644
index 000000000000..b2eb07c0a9e7
--- /dev/null
+++ b/core/tests/coretests/src/android/view/inputmethod/SelectGestureTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package android.view.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.graphics.RectF;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@ApiTest(apis = {"android.view.inputmethod.SelectGesture.Builder#setGranularity",
+ "android.view.inputmethod.SelectGesture.Builder#setSelectionArea",
+ "android.view.inputmethod.SelectGesture.Builder#setFallbackText",
+ "android.view.inputmethod.SelectGesture.Builder#build"})
+public class SelectGestureTest {
+ private static final RectF SELECTION_RECTANGLE = new RectF(1, 2, 3, 4);
+ private static final String FALLBACK_TEXT = "fallback_text";
+
+ @Test
+ public void testBuilder() {
+ SelectGesture.Builder builder = new SelectGesture.Builder();
+ SelectGesture gesture = builder.setGranularity(HandwritingGesture.GRANULARITY_WORD)
+ .setSelectionArea(SELECTION_RECTANGLE)
+ .setFallbackText(FALLBACK_TEXT).build();
+ assertNotNull(gesture);
+ assertEquals(HandwritingGesture.GRANULARITY_WORD, gesture.getGranularity());
+ assertEquals(SELECTION_RECTANGLE, gesture.getSelectionArea());
+ assertEquals(FALLBACK_TEXT, gesture.getFallbackText());
+ }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/SelectRangeGestureTest.java b/core/tests/coretests/src/android/view/inputmethod/SelectRangeGestureTest.java
new file mode 100644
index 000000000000..df63a4aaaefe
--- /dev/null
+++ b/core/tests/coretests/src/android/view/inputmethod/SelectRangeGestureTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package android.view.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.graphics.RectF;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@ApiTest(apis = {"android.view.inputmethod.SelectRangeGesture.Builder#setGranularity",
+ "android.view.inputmethod.SelectRangeGesture.Builder#setSelectionStartArea",
+ "android.view.inputmethod.SelectRangeGesture.Builder#setSelectionEndArea",
+ "android.view.inputmethod.SelectRangeGesture.Builder#setFallbackText",
+ "android.view.inputmethod.SelectRangeGesture.Builder#build"})
+public class SelectRangeGestureTest {
+ private static final RectF SELECTION_START_RECTANGLE = new RectF(1, 2, 3, 4);
+ private static final RectF SELECTION_END_RECTANGLE = new RectF(0, 2, 3, 4);
+ private static final String FALLBACK_TEXT = "fallback_text";
+
+ @Test
+ public void testBuilder() {
+ SelectRangeGesture.Builder builder = new SelectRangeGesture.Builder();
+ SelectRangeGesture gesture = builder.setGranularity(HandwritingGesture.GRANULARITY_WORD)
+ .setSelectionStartArea(SELECTION_START_RECTANGLE)
+ .setSelectionEndArea(SELECTION_END_RECTANGLE)
+ .setFallbackText(FALLBACK_TEXT).build();
+ assertNotNull(gesture);
+ assertEquals(HandwritingGesture.GRANULARITY_WORD, gesture.getGranularity());
+ assertEquals(SELECTION_START_RECTANGLE, gesture.getSelectionStartArea());
+ assertEquals(SELECTION_END_RECTANGLE, gesture.getSelectionEndArea());
+ assertEquals(FALLBACK_TEXT, gesture.getFallbackText());
+ }
+}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index ffc5ff226607..5549f88b65e0 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -259,12 +259,6 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-1878839956": {
- "message": "Marking app token %s with replacing windows.",
- "level": "DEBUG",
- "group": "WM_DEBUG_ADD_REMOVE",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"-1872288685": {
"message": "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b Callers=%s",
"level": "VERBOSE",
@@ -463,12 +457,6 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/Task.java"
},
- "-1698815688": {
- "message": "Resetting app token %s of replacing window marks.",
- "level": "DEBUG",
- "group": "WM_DEBUG_ADD_REMOVE",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"-1679411993": {
"message": "setVr2dDisplayId called for: %d",
"level": "DEBUG",
@@ -481,12 +469,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-1661704580": {
- "message": "Attempted to set replacing window on non-existing app token %s",
- "level": "WARN",
- "group": "WM_ERROR",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"-1647332198": {
"message": "remove RecentTask %s when finishing user %d",
"level": "INFO",
@@ -613,12 +595,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-1515151503": {
- "message": ">>> OPEN TRANSACTION removeReplacedWindows",
- "level": "INFO",
- "group": "WM_SHOW_TRANSACTIONS",
- "at": "com\/android\/server\/wm\/RootWindowContainer.java"
- },
"-1501564055": {
"message": "Organized TaskFragment is not ready= %s",
"level": "VERBOSE",
@@ -691,12 +667,6 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
- "-1471946192": {
- "message": "Marking app token %s with replacing child windows.",
- "level": "DEBUG",
- "group": "WM_DEBUG_ADD_REMOVE",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"-1471518109": {
"message": "Set animatingExit: reason=onAppVisibilityChanged win=%s",
"level": "DEBUG",
@@ -919,12 +889,6 @@
"group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/BackNavigationController.java"
},
- "-1270731689": {
- "message": "Attempted to set replacing window on app token with no content %s",
- "level": "WARN",
- "group": "WM_ERROR",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"-1263316010": {
"message": "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and oldRotation=%s (%d)",
"level": "VERBOSE",
@@ -1417,12 +1381,6 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
},
- "-799003045": {
- "message": "Set animatingExit: reason=remove\/replaceWindow win=%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_ANIM",
- "at": "com\/android\/server\/wm\/WindowState.java"
- },
"-787664727": {
"message": "Cannot launch dream activity due to invalid state. dream component: %s packageName: %s",
"level": "ERROR",
@@ -1453,6 +1411,12 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
+ "-778347463": {
+ "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mDisplayFrozen=%b callers=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/WindowState.java"
+ },
"-775004869": {
"message": "Not a match: %s",
"level": "DEBUG",
@@ -1963,12 +1927,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-320419645": {
- "message": "Removing replaced window: %s",
- "level": "DEBUG",
- "group": "WM_DEBUG_ADD_REMOVE",
- "at": "com\/android\/server\/wm\/WindowState.java"
- },
"-319689203": {
"message": "Reparenting to original parent: %s for %s",
"level": "INFO",
@@ -2335,12 +2293,6 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
- "38267433": {
- "message": "Attempted to reset replacing window on non-existing app token %s",
- "level": "WARN",
- "group": "WM_ERROR",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"45285419": {
"message": "startingWindow was set but startingSurface==null, couldn't remove",
"level": "VERBOSE",
@@ -2989,12 +2941,6 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
- "594260654": {
- "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mWillReplaceWindow=%b mDisplayFrozen=%b callers=%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/WindowState.java"
- },
"600140673": {
"message": "checkBootAnimationComplete: Waiting for anim complete",
"level": "INFO",
@@ -3829,12 +3775,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "1423592961": {
- "message": "<<< CLOSE TRANSACTION removeReplacedWindows",
- "level": "INFO",
- "group": "WM_SHOW_TRANSACTIONS",
- "at": "com\/android\/server\/wm\/RootWindowContainer.java"
- },
"1430336882": {
"message": "findFocusedWindow: focusedApp windows not focusable using new focus @ %s",
"level": "VERBOSE",
@@ -3901,12 +3841,6 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
- "1515161239": {
- "message": "removeDeadWindows: %s",
- "level": "WARN",
- "group": "WM_DEBUG_ADD_REMOVE",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"1518495446": {
"message": "removeWindowToken: Attempted to remove non-existing token: %s",
"level": "WARN",
@@ -4273,12 +4207,6 @@
"group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/TaskOrganizerController.java"
},
- "1921821199": {
- "message": "Preserving %s until the new one is added",
- "level": "VERBOSE",
- "group": "WM_DEBUG_ADD_REMOVE",
- "at": "com\/android\/server\/wm\/WindowState.java"
- },
"1928325128": {
"message": "Run showImeRunner",
"level": "DEBUG",
@@ -4489,12 +4417,6 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
- "2114149926": {
- "message": "Not removing %s because app died while it's visible",
- "level": "VERBOSE",
- "group": "WM_DEBUG_ADD_REMOVE",
- "at": "com\/android\/server\/wm\/WindowState.java"
- },
"2117696413": {
"message": "moveTaskToFront: moving taskId=%d",
"level": "DEBUG",
diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
index 298ad3025b00..8d1da0f7ad1b 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
@@ -63,11 +63,11 @@
android:tint="@color/bubbles_icon_tint"/>
<TextView
+ android:id="@+id/bubble_manage_menu_dont_bubble_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault"
- android:text="@string/bubbles_dont_bubble_conversation" />
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault" />
</LinearLayout>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 3082962e1a8b..9f6cf79dcbc4 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -146,6 +146,8 @@
<string name="bubbles_app_settings"><xliff:g id="notification_title" example="Android Messages">%1$s</xliff:g> settings</string>
<!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=30] -->
<string name="bubble_dismiss_text">Dismiss bubble</string>
+ <!-- Button text to stop an app from bubbling [CHAR LIMIT=60]-->
+ <string name="bubbles_dont_bubble">Don\u2019t bubble</string>
<!-- Button text to stop a conversation from bubbling [CHAR LIMIT=60]-->
<string name="bubbles_dont_bubble_conversation">Don\u2019t bubble conversation</string>
<!-- Title text for the bubbles feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=60]-->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index e5a4362e5bf0..9ccd6ebc51e2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -229,6 +229,7 @@ public class BubbleExpandedView extends LinearLayout {
options.setLaunchedFromBubble(true);
options.setPendingIntentBackgroundActivityStartMode(
MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ options.setPendingIntentBackgroundActivityLaunchAllowedByPermission(true);
Intent fillInIntent = new Intent();
// Apply flags to make behaviour match documentLaunchMode=always.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 0b947c8b9b08..deb4fd5f19bb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -844,6 +844,8 @@ public class BubbleStackView extends FrameLayout
private DismissView mDismissView;
private ViewGroup mManageMenu;
+ private TextView mManageDontBubbleText;
+ private ViewGroup mManageSettingsView;
private ImageView mManageSettingsIcon;
private TextView mManageSettingsText;
private boolean mShowingManage = false;
@@ -1217,7 +1219,11 @@ public class BubbleStackView extends FrameLayout
mUnbubbleConversationCallback.accept(mBubbleData.getSelectedBubble().getKey());
});
- mManageMenu.findViewById(R.id.bubble_manage_menu_settings_container).setOnClickListener(
+ mManageDontBubbleText = mManageMenu
+ .findViewById(R.id.bubble_manage_menu_dont_bubble_text);
+
+ mManageSettingsView = mManageMenu.findViewById(R.id.bubble_manage_menu_settings_container);
+ mManageSettingsView.setOnClickListener(
view -> {
showManageMenu(false /* show */);
final BubbleViewProvider bubble = mBubbleData.getSelectedBubble();
@@ -2868,10 +2874,19 @@ public class BubbleStackView extends FrameLayout
// name and icon.
if (show) {
final Bubble bubble = mBubbleData.getBubbleInStackWithKey(mExpandedBubble.getKey());
- if (bubble != null) {
+ if (bubble != null && !bubble.isAppBubble()) {
+ // Setup options for non app bubbles
+ mManageDontBubbleText.setText(R.string.bubbles_dont_bubble_conversation);
mManageSettingsIcon.setImageBitmap(bubble.getRawAppBadge());
mManageSettingsText.setText(getResources().getString(
R.string.bubbles_app_settings, bubble.getAppName()));
+ mManageSettingsView.setVisibility(VISIBLE);
+ } else {
+ // Setup options for app bubbles
+ mManageDontBubbleText.setText(R.string.bubbles_dont_bubble);
+ // App bubbles are not notification based
+ // so we don't show the option to go to notification settings
+ mManageSettingsView.setVisibility(GONE);
}
}
@@ -2936,6 +2951,15 @@ public class BubbleStackView extends FrameLayout
}
}
+ /**
+ * Checks whether manage menu notification settings action is available and visible
+ * Used for testing
+ */
+ @VisibleForTesting
+ public boolean isManageMenuSettingsVisible() {
+ return mManageSettingsView != null && mManageSettingsView.getVisibility() == VISIBLE;
+ }
+
private void updateExpandedBubble() {
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "updateExpandedBubble()");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 0a9c3310a883..8cb575cc96e3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -103,6 +103,7 @@ class DragResizeInputListener implements AutoCloseable {
null /* hostInputToken */,
FLAG_NOT_FOCUSABLE,
PRIVATE_FLAG_TRUSTED_OVERLAY,
+ 0 /* inputFeatures */,
TYPE_APPLICATION,
null /* windowToken */,
mFocusGrantToken,
@@ -208,6 +209,7 @@ class DragResizeInputListener implements AutoCloseable {
mDecorationSurface,
FLAG_NOT_FOCUSABLE,
PRIVATE_FLAG_TRUSTED_OVERLAY,
+ 0 /* inputFeatures */,
touchRegion);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index c3984055a278..c3ad7670d473 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -53,8 +53,6 @@ MouseCursorController::MouseCursorController(PointerControllerContext& context)
mLocked.resolvedPointerType = PointerIconStyle::TYPE_NOT_SPECIFIED;
mLocked.resourcesLoaded = false;
-
- mLocked.buttonState = 0;
}
MouseCursorController::~MouseCursorController() {
@@ -95,22 +93,6 @@ void MouseCursorController::move(float deltaX, float deltaY) {
setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
}
-void MouseCursorController::setButtonState(int32_t buttonState) {
-#if DEBUG_MOUSE_CURSOR_UPDATES
- ALOGD("Set button state 0x%08x", buttonState);
-#endif
- std::scoped_lock lock(mLock);
-
- if (mLocked.buttonState != buttonState) {
- mLocked.buttonState = buttonState;
- }
-}
-
-int32_t MouseCursorController::getButtonState() const {
- std::scoped_lock lock(mLock);
- return mLocked.buttonState;
-}
-
void MouseCursorController::setPosition(float x, float y) {
#if DEBUG_MOUSE_CURSOR_UPDATES
ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h
index 26be2a858c4e..00dc0854440e 100644
--- a/libs/input/MouseCursorController.h
+++ b/libs/input/MouseCursorController.h
@@ -45,8 +45,6 @@ public:
std::optional<FloatRect> getBounds() const;
void move(float deltaX, float deltaY);
- void setButtonState(int32_t buttonState);
- int32_t getButtonState() const;
void setPosition(float x, float y);
FloatPoint getPosition() const;
int32_t getDisplayId() const;
@@ -96,8 +94,6 @@ private:
PointerIconStyle requestedPointerType;
PointerIconStyle resolvedPointerType;
- int32_t buttonState;
-
bool animating{false};
} mLocked GUARDED_BY(mLock);
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 544edc2a716f..88e351963148 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -136,14 +136,6 @@ void PointerController::move(float deltaX, float deltaY) {
mCursorController.move(transformed.x, transformed.y);
}
-void PointerController::setButtonState(int32_t buttonState) {
- mCursorController.setButtonState(buttonState);
-}
-
-int32_t PointerController::getButtonState() const {
- return mCursorController.getButtonState();
-}
-
void PointerController::setPosition(float x, float y) {
const int32_t displayId = mCursorController.getDisplayId();
vec2 transformed;
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 6d3557c89cc7..ca14b6e9bfdc 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -50,21 +50,19 @@ public:
~PointerController() override;
- virtual std::optional<FloatRect> getBounds() const;
- virtual void move(float deltaX, float deltaY);
- virtual void setButtonState(int32_t buttonState);
- virtual int32_t getButtonState() const;
- virtual void setPosition(float x, float y);
- virtual FloatPoint getPosition() const;
- virtual int32_t getDisplayId() const;
- virtual void fade(Transition transition);
- virtual void unfade(Transition transition);
- virtual void setDisplayViewport(const DisplayViewport& viewport);
-
- virtual void setPresentation(Presentation presentation);
- virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
- BitSet32 spotIdBits, int32_t displayId);
- virtual void clearSpots();
+ std::optional<FloatRect> getBounds() const override;
+ void move(float deltaX, float deltaY) override;
+ void setPosition(float x, float y) override;
+ FloatPoint getPosition() const override;
+ int32_t getDisplayId() const override;
+ void fade(Transition transition) override;
+ void unfade(Transition transition) override;
+ void setDisplayViewport(const DisplayViewport& viewport) override;
+
+ void setPresentation(Presentation presentation) override;
+ void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
+ BitSet32 spotIdBits, int32_t displayId) override;
+ void clearSpots() override;
void updatePointerIcon(PointerIconStyle iconId);
void setCustomPointerIcon(const SpriteIcon& icon);
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index 7946baee200a..f939f523d3fa 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -280,7 +280,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
}
case DO_NOTIFY_TV_MESSAGE: {
SomeArgs args = (SomeArgs) msg.obj;
- mTvInputSessionImpl.onTvMessageReceived((String) args.arg1, (Bundle) args.arg2);
+ mTvInputSessionImpl.onTvMessageReceived((Integer) args.arg1, (Bundle) args.arg2);
break;
}
default: {
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 4e380c41ccdb..0d283fa87c19 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1512,7 +1512,7 @@ public abstract class TvInputService extends Service {
* See {@link TvInputManager#TV_MESSAGE_KEY_SUBTYPE} for more information on
* how to parse this data.
*/
- public void onTvMessage(@NonNull @TvInputManager.TvMessageType String type,
+ public void onTvMessage(@TvInputManager.TvMessageType int type,
@NonNull Bundle data) {
}
@@ -2065,7 +2065,7 @@ public abstract class TvInputService extends Service {
onAdBufferReady(buffer);
}
- void onTvMessageReceived(String type, Bundle data) {
+ void onTvMessageReceived(int type, Bundle data) {
onTvMessage(type, data);
}
diff --git a/packages/SettingsLib/DeviceStateRotationLock/Android.bp b/packages/SettingsLib/DeviceStateRotationLock/Android.bp
index c642bd14ed79..103309a43bb8 100644
--- a/packages/SettingsLib/DeviceStateRotationLock/Android.bp
+++ b/packages/SettingsLib/DeviceStateRotationLock/Android.bp
@@ -10,7 +10,10 @@ package {
android_library {
name: "SettingsLibDeviceStateRotationLock",
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
min_sdk_version: "21",
}
diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
index 10b004e1b243..76e1df1459e3 100644
--- a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
+++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
@@ -57,17 +57,19 @@ public final class DeviceStateRotationLockSettingsManager {
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
private final Set<DeviceStateRotationLockSettingsListener> mListeners = new HashSet<>();
private final SecureSettings mSecureSettings;
- private String[] mDeviceStateRotationLockDefaults;
- private SparseIntArray mDeviceStateRotationLockSettings;
- private SparseIntArray mDeviceStateDefaultRotationLockSettings;
- private SparseIntArray mDeviceStateRotationLockFallbackSettings;
+ private final PosturesHelper mPosturesHelper;
+ private String[] mPostureRotationLockDefaults;
+ private SparseIntArray mPostureRotationLockSettings;
+ private SparseIntArray mPostureDefaultRotationLockSettings;
+ private SparseIntArray mPostureRotationLockFallbackSettings;
private String mLastSettingValue;
private List<SettableDeviceState> mSettableDeviceStates;
@VisibleForTesting
DeviceStateRotationLockSettingsManager(Context context, SecureSettings secureSettings) {
- this.mSecureSettings = secureSettings;
- mDeviceStateRotationLockDefaults =
+ mSecureSettings = secureSettings;
+ mPosturesHelper = new PosturesHelper(context);
+ mPostureRotationLockDefaults =
context.getResources()
.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
loadDefaults();
@@ -134,13 +136,14 @@ public final class DeviceStateRotationLockSettingsManager {
/** Updates the rotation lock setting for a specified device state. */
public void updateSetting(int deviceState, boolean rotationLocked) {
- if (mDeviceStateRotationLockFallbackSettings.indexOfKey(deviceState) >= 0) {
- // The setting for this device state is IGNORED, and has a fallback device state.
- // The setting for that fallback device state should be the changed in this case.
- deviceState = mDeviceStateRotationLockFallbackSettings.get(deviceState);
+ int posture = mPosturesHelper.deviceStateToPosture(deviceState);
+ if (mPostureRotationLockFallbackSettings.indexOfKey(posture) >= 0) {
+ // The setting for this device posture is IGNORED, and has a fallback posture.
+ // The setting for that fallback posture should be the changed in this case.
+ posture = mPostureRotationLockFallbackSettings.get(posture);
}
- mDeviceStateRotationLockSettings.put(
- deviceState,
+ mPostureRotationLockSettings.put(
+ posture,
rotationLocked
? DEVICE_STATE_ROTATION_LOCK_LOCKED
: DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
@@ -159,22 +162,23 @@ public final class DeviceStateRotationLockSettingsManager {
*/
@Settings.Secure.DeviceStateRotationLockSetting
public int getRotationLockSetting(int deviceState) {
- int rotationLockSetting = mDeviceStateRotationLockSettings.get(
- deviceState, /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
+ int devicePosture = mPosturesHelper.deviceStateToPosture(deviceState);
+ int rotationLockSetting = mPostureRotationLockSettings.get(
+ devicePosture, /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
- rotationLockSetting = getFallbackRotationLockSetting(deviceState);
+ rotationLockSetting = getFallbackRotationLockSetting(devicePosture);
}
return rotationLockSetting;
}
- private int getFallbackRotationLockSetting(int deviceState) {
- int indexOfFallbackState = mDeviceStateRotationLockFallbackSettings.indexOfKey(deviceState);
- if (indexOfFallbackState < 0) {
+ private int getFallbackRotationLockSetting(int devicePosture) {
+ int indexOfFallback = mPostureRotationLockFallbackSettings.indexOfKey(devicePosture);
+ if (indexOfFallback < 0) {
Log.w(TAG, "Setting is ignored, but no fallback was specified.");
return DEVICE_STATE_ROTATION_LOCK_IGNORED;
}
- int fallbackState = mDeviceStateRotationLockFallbackSettings.valueAt(indexOfFallbackState);
- return mDeviceStateRotationLockSettings.get(fallbackState,
+ int fallbackPosture = mPostureRotationLockFallbackSettings.valueAt(indexOfFallback);
+ return mPostureRotationLockSettings.get(fallbackPosture,
/* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
}
@@ -189,8 +193,8 @@ public final class DeviceStateRotationLockSettingsManager {
* DEVICE_STATE_ROTATION_LOCK_UNLOCKED}.
*/
public boolean isRotationLockedForAllStates() {
- for (int i = 0; i < mDeviceStateRotationLockSettings.size(); i++) {
- if (mDeviceStateRotationLockSettings.valueAt(i)
+ for (int i = 0; i < mPostureRotationLockSettings.size(); i++) {
+ if (mPostureRotationLockSettings.valueAt(i)
== DEVICE_STATE_ROTATION_LOCK_UNLOCKED) {
return false;
}
@@ -221,7 +225,7 @@ public final class DeviceStateRotationLockSettingsManager {
fallbackOnDefaults();
return;
}
- mDeviceStateRotationLockSettings = new SparseIntArray(values.length / 2);
+ mPostureRotationLockSettings = new SparseIntArray(values.length / 2);
int key;
int value;
@@ -230,7 +234,7 @@ public final class DeviceStateRotationLockSettingsManager {
key = Integer.parseInt(values[i++]);
value = Integer.parseInt(values[i++]);
boolean isPersistedValueIgnored = value == DEVICE_STATE_ROTATION_LOCK_IGNORED;
- boolean isDefaultValueIgnored = mDeviceStateDefaultRotationLockSettings.get(key)
+ boolean isDefaultValueIgnored = mPostureDefaultRotationLockSettings.get(key)
== DEVICE_STATE_ROTATION_LOCK_IGNORED;
if (isPersistedValueIgnored != isDefaultValueIgnored) {
Log.w(TAG, "Conflict for ignored device state " + key
@@ -238,7 +242,7 @@ public final class DeviceStateRotationLockSettingsManager {
fallbackOnDefaults();
return;
}
- mDeviceStateRotationLockSettings.put(key, value);
+ mPostureRotationLockSettings.put(key, value);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error deserializing one of the saved settings", e);
fallbackOnDefaults();
@@ -253,7 +257,7 @@ public final class DeviceStateRotationLockSettingsManager {
*/
@VisibleForTesting
public void resetStateForTesting(Resources resources) {
- mDeviceStateRotationLockDefaults =
+ mPostureRotationLockDefaults =
resources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
fallbackOnDefaults();
}
@@ -264,23 +268,23 @@ public final class DeviceStateRotationLockSettingsManager {
}
private void persistSettings() {
- if (mDeviceStateRotationLockSettings.size() == 0) {
+ if (mPostureRotationLockSettings.size() == 0) {
persistSettingIfChanged(/* newSettingValue= */ "");
return;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder
- .append(mDeviceStateRotationLockSettings.keyAt(0))
+ .append(mPostureRotationLockSettings.keyAt(0))
.append(SEPARATOR_REGEX)
- .append(mDeviceStateRotationLockSettings.valueAt(0));
+ .append(mPostureRotationLockSettings.valueAt(0));
- for (int i = 1; i < mDeviceStateRotationLockSettings.size(); i++) {
+ for (int i = 1; i < mPostureRotationLockSettings.size(); i++) {
stringBuilder
.append(SEPARATOR_REGEX)
- .append(mDeviceStateRotationLockSettings.keyAt(i))
+ .append(mPostureRotationLockSettings.keyAt(i))
.append(SEPARATOR_REGEX)
- .append(mDeviceStateRotationLockSettings.valueAt(i));
+ .append(mPostureRotationLockSettings.valueAt(i));
}
persistSettingIfChanged(stringBuilder.toString());
}
@@ -300,22 +304,20 @@ public final class DeviceStateRotationLockSettingsManager {
}
private void loadDefaults() {
- mSettableDeviceStates = new ArrayList<>(mDeviceStateRotationLockDefaults.length);
- mDeviceStateDefaultRotationLockSettings = new SparseIntArray(
- mDeviceStateRotationLockDefaults.length);
- mDeviceStateRotationLockSettings = new SparseIntArray(
- mDeviceStateRotationLockDefaults.length);
- mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1);
- for (String entry : mDeviceStateRotationLockDefaults) {
+ mSettableDeviceStates = new ArrayList<>(mPostureRotationLockDefaults.length);
+ mPostureDefaultRotationLockSettings = new SparseIntArray(
+ mPostureRotationLockDefaults.length);
+ mPostureRotationLockSettings = new SparseIntArray(mPostureRotationLockDefaults.length);
+ mPostureRotationLockFallbackSettings = new SparseIntArray(1);
+ for (String entry : mPostureRotationLockDefaults) {
String[] values = entry.split(SEPARATOR_REGEX);
try {
- int deviceState = Integer.parseInt(values[0]);
+ int posture = Integer.parseInt(values[0]);
int rotationLockSetting = Integer.parseInt(values[1]);
if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
if (values.length == 3) {
- int fallbackDeviceState = Integer.parseInt(values[2]);
- mDeviceStateRotationLockFallbackSettings.put(deviceState,
- fallbackDeviceState);
+ int fallbackPosture = Integer.parseInt(values[2]);
+ mPostureRotationLockFallbackSettings.put(posture, fallbackPosture);
} else {
Log.w(TAG,
"Rotation lock setting is IGNORED, but values have unexpected "
@@ -324,9 +326,14 @@ public final class DeviceStateRotationLockSettingsManager {
}
}
boolean isSettable = rotationLockSetting != DEVICE_STATE_ROTATION_LOCK_IGNORED;
- mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
- mDeviceStateRotationLockSettings.put(deviceState, rotationLockSetting);
- mDeviceStateDefaultRotationLockSettings.put(deviceState, rotationLockSetting);
+ Integer deviceState = mPosturesHelper.postureToDeviceState(posture);
+ if (deviceState != null) {
+ mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
+ } else {
+ Log.wtf(TAG, "No matching device state for posture: " + posture);
+ }
+ mPostureRotationLockSettings.put(posture, rotationLockSetting);
+ mPostureDefaultRotationLockSettings.put(posture, rotationLockSetting);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error parsing settings entry. Entry was: " + entry, e);
return;
@@ -338,13 +345,11 @@ public final class DeviceStateRotationLockSettingsManager {
public void dump(IndentingPrintWriter pw) {
pw.println("DeviceStateRotationLockSettingsManager");
pw.increaseIndent();
- pw.println("mDeviceStateRotationLockDefaults: " + Arrays.toString(
- mDeviceStateRotationLockDefaults));
- pw.println("mDeviceStateDefaultRotationLockSettings: "
- + mDeviceStateDefaultRotationLockSettings);
- pw.println("mDeviceStateRotationLockSettings: " + mDeviceStateRotationLockSettings);
- pw.println("mDeviceStateRotationLockFallbackSettings: "
- + mDeviceStateRotationLockFallbackSettings);
+ pw.println("mPostureRotationLockDefaults: "
+ + Arrays.toString(mPostureRotationLockDefaults));
+ pw.println("mPostureDefaultRotationLockSettings: " + mPostureDefaultRotationLockSettings);
+ pw.println("mDeviceStateRotationLockSettings: " + mPostureRotationLockSettings);
+ pw.println("mPostureRotationLockFallbackSettings: " + mPostureRotationLockFallbackSettings);
pw.println("mSettableDeviceStates: " + mSettableDeviceStates);
pw.println("mLastSettingValue: " + mLastSettingValue);
pw.decreaseIndent();
diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt
new file mode 100644
index 000000000000..9c70be9c1f66
--- /dev/null
+++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package com.android.settingslib.devicestate
+
+import android.content.Context
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_FOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNFOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNKNOWN
+import android.provider.Settings.Secure.DeviceStateRotationLockKey
+import com.android.internal.R
+
+/** Helps to convert between device state and posture. */
+class PosturesHelper(context: Context) {
+
+ private val foldedDeviceStates =
+ context.resources.getIntArray(R.array.config_foldedDeviceStates)
+ private val halfFoldedDeviceStates =
+ context.resources.getIntArray(R.array.config_halfFoldedDeviceStates)
+ private val unfoldedDeviceStates =
+ context.resources.getIntArray(R.array.config_openDeviceStates)
+
+ @DeviceStateRotationLockKey
+ fun deviceStateToPosture(deviceState: Int): Int {
+ return when (deviceState) {
+ in foldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_FOLDED
+ in halfFoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
+ in unfoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_UNFOLDED
+ else -> DEVICE_STATE_ROTATION_KEY_UNKNOWN
+ }
+ }
+
+ fun postureToDeviceState(@DeviceStateRotationLockKey posture: Int): Int? {
+ return when (posture) {
+ DEVICE_STATE_ROTATION_KEY_FOLDED -> foldedDeviceStates.firstOrNull()
+ DEVICE_STATE_ROTATION_KEY_HALF_FOLDED -> halfFoldedDeviceStates.firstOrNull()
+ DEVICE_STATE_ROTATION_KEY_UNFOLDED -> unfoldedDeviceStates.firstOrNull()
+ else -> null
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt
index ca88f8da63c9..215f6b964ad3 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt
@@ -16,7 +16,6 @@
package com.android.settingslib.spa.framework.common
-import android.app.settings.SettingsEnums
import android.os.Bundle
// Defines the category of the log, for quick filter
@@ -32,14 +31,14 @@ enum class LogCategory {
}
// Defines the log events in Spa.
-enum class LogEvent(val action: Int) {
+enum class LogEvent {
// Page related events.
- PAGE_ENTER(SettingsEnums.PAGE_VISIBLE),
- PAGE_LEAVE(SettingsEnums.PAGE_HIDE),
+ PAGE_ENTER,
+ PAGE_LEAVE,
// Entry related events.
- ENTRY_CLICK(SettingsEnums.ACTION_SETTINGS_TILE_CLICK),
- ENTRY_SWITCH(SettingsEnums.ACTION_SETTINGS_PREFERENCE_CHANGE),
+ ENTRY_CLICK,
+ ENTRY_SWITCH,
}
internal const val LOG_DATA_DISPLAY_NAME = "name"
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
index 0fa15eb6bc0c..fdefcde3a170 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
@@ -70,12 +70,20 @@ public class DeviceStateRotationLockSettingsManagerTest {
when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
when(mMockContext.getResources()).thenReturn(mMockResources);
when(mMockContext.getContentResolver()).thenReturn(context.getContentResolver());
+ when(mMockResources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults))
+ .thenReturn(new String[]{"0:1", "1:0:2", "2:2"});
+ when(mMockResources.getIntArray(R.array.config_foldedDeviceStates))
+ .thenReturn(new int[]{0});
+ when(mMockResources.getIntArray(R.array.config_halfFoldedDeviceStates))
+ .thenReturn(new int[]{1});
+ when(mMockResources.getIntArray(R.array.config_openDeviceStates))
+ .thenReturn(new int[]{2});
mFakeSecureSettings.registerContentObserver(
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
/* notifyForDescendents= */ false, //NOTYPO
mContentObserver,
UserHandle.USER_CURRENT);
- mManager = new DeviceStateRotationLockSettingsManager(context, mFakeSecureSettings);
+ mManager = new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings);
}
@Test
@@ -109,7 +117,7 @@ public class DeviceStateRotationLockSettingsManagerTest {
public void getSettableDeviceStates_returnsExpectedValuesInOriginalOrder() {
when(mMockResources.getStringArray(
R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
- new String[]{"2:2", "4:0", "1:1", "0:0"});
+ new String[]{"2:1", "1:0:1", "0:2"});
List<SettableDeviceState> settableDeviceStates =
DeviceStateRotationLockSettingsManager.getInstance(
@@ -117,9 +125,8 @@ public class DeviceStateRotationLockSettingsManagerTest {
assertThat(settableDeviceStates).containsExactly(
new SettableDeviceState(/* deviceState= */ 2, /* isSettable= */ true),
- new SettableDeviceState(/* deviceState= */ 4, /* isSettable= */ false),
- new SettableDeviceState(/* deviceState= */ 1, /* isSettable= */ true),
- new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ false)
+ new SettableDeviceState(/* deviceState= */ 1, /* isSettable= */ false),
+ new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ true)
).inOrder();
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt
index 280e7ed9ea2e..23fcb691ddb4 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt
@@ -15,163 +15,166 @@
*/
package com.android.systemui.surfaceeffects.shaderutil
-/** A common utility functions that are used for computing shaders. */
-class ShaderUtilLibrary {
+/** Common utility functions that are used for computing shaders. */
+object ShaderUtilLibrary {
// language=AGSL
- companion object {
- const val SHADER_LIB =
- """
- float triangleNoise(vec2 n) {
- n = fract(n * vec2(5.3987, 5.4421));
- n += dot(n.yx, n.xy + vec2(21.5351, 14.3137));
- float xy = n.x * n.y;
- // compute in [0..2[ and remap to [-1.0..1.0[
- return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;
+ const val SHADER_LIB =
+ """
+ float triangleNoise(vec2 n) {
+ n = fract(n * vec2(5.3987, 5.4421));
+ n += dot(n.yx, n.xy + vec2(21.5351, 14.3137));
+ float xy = n.x * n.y;
+ // compute in [0..2[ and remap to [-1.0..1.0[
+ return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;
+ }
+
+ const float PI = 3.1415926535897932384626;
+
+ float sparkles(vec2 uv, float t) {
+ float n = triangleNoise(uv);
+ float s = 0.0;
+ for (float i = 0; i < 4; i += 1) {
+ float l = i * 0.01;
+ float h = l + 0.1;
+ float o = smoothstep(n - l, h, n);
+ o *= abs(sin(PI * o * (t + 0.55 * i)));
+ s += o;
}
-
- const float PI = 3.1415926535897932384626;
-
- float sparkles(vec2 uv, float t) {
- float n = triangleNoise(uv);
- float s = 0.0;
- for (float i = 0; i < 4; i += 1) {
- float l = i * 0.01;
- float h = l + 0.1;
- float o = smoothstep(n - l, h, n);
- o *= abs(sin(PI * o * (t + 0.55 * i)));
- s += o;
- }
- return s;
- }
-
- vec2 distort(vec2 p, float time, float distort_amount_radial,
- float distort_amount_xy) {
- float angle = atan(p.y, p.x);
- return p + vec2(sin(angle * 8 + time * 0.003 + 1.641),
- cos(angle * 5 + 2.14 + time * 0.00412)) * distort_amount_radial
- + vec2(sin(p.x * 0.01 + time * 0.00215 + 0.8123),
- cos(p.y * 0.01 + time * 0.005931)) * distort_amount_xy;
- }
-
- // Perceived luminosity (L′), not absolute luminosity.
- half getLuminosity(vec3 c) {
- return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
- }
-
- // Creates a luminosity mask and clamp to the legal range.
- vec3 maskLuminosity(vec3 dest, float lum) {
- dest.rgb *= vec3(lum);
- // Clip back into the legal range
- dest = clamp(dest, vec3(0.), vec3(1.0));
- return dest;
- }
-
- // Return range [-1, 1].
- vec3 hash(vec3 p) {
- p = fract(p * vec3(.3456, .1234, .9876));
- p += dot(p, p.yxz + 43.21);
- p = (p.xxy + p.yxx) * p.zyx;
- return (fract(sin(p) * 4567.1234567) - .5) * 2.;
- }
-
- // Skew factors (non-uniform).
- const half SKEW = 0.3333333; // 1/3
- const half UNSKEW = 0.1666667; // 1/6
-
- // Return range roughly [-1,1].
- // It's because the hash function (that returns a random gradient vector) returns
- // different magnitude of vectors. Noise doesn't have to be in the precise range thus
- // skipped normalize.
- half simplex3d(vec3 p) {
- // Skew the input coordinate, so that we get squashed cubical grid
- vec3 s = floor(p + (p.x + p.y + p.z) * SKEW);
-
- // Unskew back
- vec3 u = s - (s.x + s.y + s.z) * UNSKEW;
-
- // Unskewed coordinate that is relative to p, to compute the noise contribution
- // based on the distance.
- vec3 c0 = p - u;
-
- // We have six simplices (in this case tetrahedron, since we are in 3D) that we
- // could possibly in.
- // Here, we are finding the correct tetrahedron (simplex shape), and traverse its
- // four vertices (c0..3) when computing noise contribution.
- // The way we find them is by comparing c0's x,y,z values.
- // For example in 2D, we can find the triangle (simplex shape in 2D) that we are in
- // by comparing x and y values. i.e. x>y lower, x<y, upper triangle.
- // Same applies in 3D.
- //
- // Below indicates the offsets (or offset directions) when c0=(x0,y0,z0)
- // x0>y0>z0: (1,0,0), (1,1,0), (1,1,1)
- // x0>z0>y0: (1,0,0), (1,0,1), (1,1,1)
- // z0>x0>y0: (0,0,1), (1,0,1), (1,1,1)
- // z0>y0>x0: (0,0,1), (0,1,1), (1,1,1)
- // y0>z0>x0: (0,1,0), (0,1,1), (1,1,1)
- // y0>x0>z0: (0,1,0), (1,1,0), (1,1,1)
- //
- // The rule is:
- // * For offset1, set 1 at the max component, otherwise 0.
- // * For offset2, set 0 at the min component, otherwise 1.
- // * For offset3, set 1 for all.
- //
- // Encode x0-y0, y0-z0, z0-x0 in a vec3
- vec3 en = c0 - c0.yzx;
- // Each represents whether x0>y0, y0>z0, z0>x0
- en = step(vec3(0.), en);
- // en.zxy encodes z0>x0, x0>y0, y0>x0
- vec3 offset1 = en * (1. - en.zxy); // find max
- vec3 offset2 = 1. - en.zxy * (1. - en); // 1-(find min)
- vec3 offset3 = vec3(1.);
-
- vec3 c1 = c0 - offset1 + UNSKEW;
- vec3 c2 = c0 - offset2 + UNSKEW * 2.;
- vec3 c3 = c0 - offset3 + UNSKEW * 3.;
-
- // Kernel summation: dot(max(0, r^2-d^2))^4, noise contribution)
- //
- // First compute d^2, squared distance to the point.
- vec4 w; // w = max(0, r^2 - d^2))
- w.x = dot(c0, c0);
- w.y = dot(c1, c1);
- w.z = dot(c2, c2);
- w.w = dot(c3, c3);
-
- // Noise contribution should decay to zero before they cross the simplex boundary.
- // Usually r^2 is 0.5 or 0.6;
- // 0.5 ensures continuity but 0.6 increases the visual quality for the application
- // where discontinuity isn't noticeable.
- w = max(0.6 - w, 0.);
-
- // Noise contribution from each point.
- vec4 nc;
- nc.x = dot(hash(s), c0);
- nc.y = dot(hash(s + offset1), c1);
- nc.z = dot(hash(s + offset2), c2);
- nc.w = dot(hash(s + offset3), c3);
-
- nc *= w*w*w*w;
-
- // Add all the noise contributions.
- // Should multiply by the possible max contribution to adjust the range in [-1,1].
- return dot(vec4(32.), nc);
- }
-
- // Random rotations.
- // The way you create fractal noise is layering simplex noise with some rotation.
- // To make random cloud looking noise, the rotations should not align. (Otherwise it
- // creates patterned noise).
- // Below rotations only rotate in one axis.
- const mat3 rot1 = mat3(1.0, 0. ,0., 0., 0.15, -0.98, 0., 0.98, 0.15);
- const mat3 rot2 = mat3(-0.95, 0. ,-0.3, 0., 1., 0., 0.3, 0., -0.95);
- const mat3 rot3 = mat3(1.0, 0. ,0., 0., -0.44, -0.89, 0., 0.89, -0.44);
-
- // Octave = 4
- // Divide each coefficient by 3 to produce more grainy noise.
- half simplex3d_fractal(vec3 mat) {
- return 0.675 * simplex3d(mat * rot1) + 0.225 * simplex3d(2.0 * mat * rot2)
- + 0.075 * simplex3d(4.0 * mat * rot3) + 0.025 * simplex3d(8.0 * mat);
- }
- """
- }
+ return s;
+ }
+
+ vec2 distort(vec2 p, float time, float distort_amount_radial,
+ float distort_amount_xy) {
+ float angle = atan(p.y, p.x);
+ return p + vec2(sin(angle * 8 + time * 0.003 + 1.641),
+ cos(angle * 5 + 2.14 + time * 0.00412)) * distort_amount_radial
+ + vec2(sin(p.x * 0.01 + time * 0.00215 + 0.8123),
+ cos(p.y * 0.01 + time * 0.005931)) * distort_amount_xy;
+ }
+
+ // Perceived luminosity (L′), not absolute luminosity.
+ half getLuminosity(vec3 c) {
+ return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
+ }
+
+ // Creates a luminosity mask and clamp to the legal range.
+ vec3 maskLuminosity(vec3 dest, float lum) {
+ dest.rgb *= vec3(lum);
+ // Clip back into the legal range
+ dest = clamp(dest, vec3(0.), vec3(1.0));
+ return dest;
+ }
+
+ // Return range [-1, 1].
+ vec3 hash(vec3 p) {
+ p = fract(p * vec3(.3456, .1234, .9876));
+ p += dot(p, p.yxz + 43.21);
+ p = (p.xxy + p.yxx) * p.zyx;
+ return (fract(sin(p) * 4567.1234567) - .5) * 2.;
+ }
+
+ // Skew factors (non-uniform).
+ const half SKEW = 0.3333333; // 1/3
+ const half UNSKEW = 0.1666667; // 1/6
+
+ // Return range roughly [-1,1].
+ // It's because the hash function (that returns a random gradient vector) returns
+ // different magnitude of vectors. Noise doesn't have to be in the precise range thus
+ // skipped normalize.
+ half simplex3d(vec3 p) {
+ // Skew the input coordinate, so that we get squashed cubical grid
+ vec3 s = floor(p + (p.x + p.y + p.z) * SKEW);
+
+ // Unskew back
+ vec3 u = s - (s.x + s.y + s.z) * UNSKEW;
+
+ // Unskewed coordinate that is relative to p, to compute the noise contribution
+ // based on the distance.
+ vec3 c0 = p - u;
+
+ // We have six simplices (in this case tetrahedron, since we are in 3D) that we
+ // could possibly in.
+ // Here, we are finding the correct tetrahedron (simplex shape), and traverse its
+ // four vertices (c0..3) when computing noise contribution.
+ // The way we find them is by comparing c0's x,y,z values.
+ // For example in 2D, we can find the triangle (simplex shape in 2D) that we are in
+ // by comparing x and y values. i.e. x>y lower, x<y, upper triangle.
+ // Same applies in 3D.
+ //
+ // Below indicates the offsets (or offset directions) when c0=(x0,y0,z0)
+ // x0>y0>z0: (1,0,0), (1,1,0), (1,1,1)
+ // x0>z0>y0: (1,0,0), (1,0,1), (1,1,1)
+ // z0>x0>y0: (0,0,1), (1,0,1), (1,1,1)
+ // z0>y0>x0: (0,0,1), (0,1,1), (1,1,1)
+ // y0>z0>x0: (0,1,0), (0,1,1), (1,1,1)
+ // y0>x0>z0: (0,1,0), (1,1,0), (1,1,1)
+ //
+ // The rule is:
+ // * For offset1, set 1 at the max component, otherwise 0.
+ // * For offset2, set 0 at the min component, otherwise 1.
+ // * For offset3, set 1 for all.
+ //
+ // Encode x0-y0, y0-z0, z0-x0 in a vec3
+ vec3 en = c0 - c0.yzx;
+ // Each represents whether x0>y0, y0>z0, z0>x0
+ en = step(vec3(0.), en);
+ // en.zxy encodes z0>x0, x0>y0, y0>x0
+ vec3 offset1 = en * (1. - en.zxy); // find max
+ vec3 offset2 = 1. - en.zxy * (1. - en); // 1-(find min)
+ vec3 offset3 = vec3(1.);
+
+ vec3 c1 = c0 - offset1 + UNSKEW;
+ vec3 c2 = c0 - offset2 + UNSKEW * 2.;
+ vec3 c3 = c0 - offset3 + UNSKEW * 3.;
+
+ // Kernel summation: dot(max(0, r^2-d^2))^4, noise contribution)
+ //
+ // First compute d^2, squared distance to the point.
+ vec4 w; // w = max(0, r^2 - d^2))
+ w.x = dot(c0, c0);
+ w.y = dot(c1, c1);
+ w.z = dot(c2, c2);
+ w.w = dot(c3, c3);
+
+ // Noise contribution should decay to zero before they cross the simplex boundary.
+ // Usually r^2 is 0.5 or 0.6;
+ // 0.5 ensures continuity but 0.6 increases the visual quality for the application
+ // where discontinuity isn't noticeable.
+ w = max(0.6 - w, 0.);
+
+ // Noise contribution from each point.
+ vec4 nc;
+ nc.x = dot(hash(s), c0);
+ nc.y = dot(hash(s + offset1), c1);
+ nc.z = dot(hash(s + offset2), c2);
+ nc.w = dot(hash(s + offset3), c3);
+
+ nc *= w*w*w*w;
+
+ // Add all the noise contributions.
+ // Should multiply by the possible max contribution to adjust the range in [-1,1].
+ return dot(vec4(32.), nc);
+ }
+
+ // Random rotations.
+ // The way you create fractal noise is layering simplex noise with some rotation.
+ // To make random cloud looking noise, the rotations should not align. (Otherwise it
+ // creates patterned noise).
+ // Below rotations only rotate in one axis.
+ const mat3 rot1 = mat3(1.0, 0. ,0., 0., 0.15, -0.98, 0., 0.98, 0.15);
+ const mat3 rot2 = mat3(-0.95, 0. ,-0.3, 0., 1., 0., 0.3, 0., -0.95);
+ const mat3 rot3 = mat3(1.0, 0. ,0., 0., -0.44, -0.89, 0., 0.89, -0.44);
+
+ // Octave = 4
+ // Divide each coefficient by 3 to produce more grainy noise.
+ half simplex3d_fractal(vec3 p) {
+ return 0.675 * simplex3d(p * rot1) + 0.225 * simplex3d(2.0 * p * rot2)
+ + 0.075 * simplex3d(4.0 * p * rot3) + 0.025 * simplex3d(8.0 * p);
+ }
+
+ // Screen blend
+ vec3 screen(vec3 dest, vec3 src) {
+ return dest + src - dest * src;
+ }
+ """
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt
index 0e2266734274..d1ba7c4de35c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt
@@ -36,6 +36,7 @@ class TurbulenceNoiseShader(useFractal: Boolean = false) :
uniform float in_aspectRatio;
uniform float in_opacity;
uniform float in_pixelDensity;
+ uniform float in_inverseLuma;
layout(color) uniform vec4 in_color;
layout(color) uniform vec4 in_backgroundColor;
"""
@@ -47,7 +48,7 @@ class TurbulenceNoiseShader(useFractal: Boolean = false) :
uv.x *= in_aspectRatio;
vec3 noiseP = vec3(uv + in_noiseMove.xy, in_noiseMove.z) * in_gridNum;
- float luma = simplex3d(noiseP) * in_opacity;
+ float luma = abs(in_inverseLuma - simplex3d(noiseP)) * in_opacity;
vec3 mask = maskLuminosity(in_color.rgb, luma);
vec3 color = in_backgroundColor.rgb + mask * 0.6;
@@ -69,7 +70,7 @@ class TurbulenceNoiseShader(useFractal: Boolean = false) :
uv.x *= in_aspectRatio;
vec3 noiseP = vec3(uv + in_noiseMove.xy, in_noiseMove.z) * in_gridNum;
- float luma = simplex3d_fractal(noiseP) * in_opacity;
+ float luma = abs(in_inverseLuma - simplex3d_fractal(noiseP)) * in_opacity;
vec3 mask = maskLuminosity(in_color.rgb, luma);
vec3 color = in_backgroundColor.rgb + mask * 0.6;
@@ -123,6 +124,17 @@ class TurbulenceNoiseShader(useFractal: Boolean = false) :
setFloatUniform("in_aspectRatio", width / max(height, 0.001f))
}
+ /**
+ * Sets whether to inverse the luminosity of the noise.
+ *
+ * By default noise will be used as a luma matte as is. This means that you will see color in
+ * the brighter area. If you want to invert it, meaning blend color onto the darker side, set to
+ * true.
+ */
+ fun setInverseNoiseLuminosity(inverse: Boolean) {
+ setFloatUniform("in_inverseLuma", if (inverse) 1f else 0f)
+ }
+
/** Current noise movements in x, y, and z axes. */
var noiseOffsetX: Float = 0f
private set
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index 00c0a0b3e7b3..e73afe74c03d 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -29,14 +29,15 @@ import com.android.systemui.plugins.ClockMetadata
import com.android.systemui.plugins.ClockProvider
import com.android.systemui.plugins.ClockProviderPlugin
import com.android.systemui.plugins.ClockSettings
+import com.android.systemui.plugins.PluginLifecycleManager
import com.android.systemui.plugins.PluginListener
import com.android.systemui.plugins.PluginManager
import com.android.systemui.util.Assert
+import java.util.concurrent.atomic.AtomicBoolean
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
-private val TAG = ClockRegistry::class.simpleName!!
private const val DEBUG = true
private val KEY_TIMESTAMP = "appliedTimestamp"
@@ -51,7 +52,10 @@ open class ClockRegistry(
val handleAllUsers: Boolean,
defaultClockProvider: ClockProvider,
val fallbackClockId: ClockId = DEFAULT_CLOCK_ID,
+ val keepAllLoaded: Boolean,
+ val subTag: String,
) {
+ private val TAG = "${ClockRegistry::class.simpleName} ($subTag)"
interface ClockChangeListener {
// Called when the active clock changes
fun onCurrentClockChanged() {}
@@ -76,11 +80,85 @@ open class ClockRegistry(
private val pluginListener =
object : PluginListener<ClockProviderPlugin> {
- override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) =
- connectClocks(plugin)
+ override fun onPluginAttached(manager: PluginLifecycleManager<ClockProviderPlugin>) {
+ manager.loadPlugin()
+ }
+
+ override fun onPluginLoaded(
+ plugin: ClockProviderPlugin,
+ pluginContext: Context,
+ manager: PluginLifecycleManager<ClockProviderPlugin>
+ ) {
+ var isClockListChanged = false
+ for (clock in plugin.getClocks()) {
+ val id = clock.clockId
+ var isNew = false
+ val info =
+ availableClocks.getOrPut(id) {
+ isNew = true
+ ClockInfo(clock, plugin, manager)
+ }
+
+ if (isNew) {
+ isClockListChanged = true
+ onConnected(id)
+ }
+
+ if (manager != info.manager) {
+ Log.e(
+ TAG,
+ "Clock Id conflict on load: $id is registered to another provider"
+ )
+ continue
+ }
+
+ info.provider = plugin
+ onLoaded(id)
+ }
+
+ if (isClockListChanged) {
+ triggerOnAvailableClocksChanged()
+ }
+ verifyLoadedProviders()
+ }
- override fun onPluginDisconnected(plugin: ClockProviderPlugin) =
- disconnectClocks(plugin)
+ override fun onPluginUnloaded(
+ plugin: ClockProviderPlugin,
+ manager: PluginLifecycleManager<ClockProviderPlugin>
+ ) {
+ for (clock in plugin.getClocks()) {
+ val id = clock.clockId
+ val info = availableClocks[id]
+ if (info?.manager != manager) {
+ Log.e(
+ TAG,
+ "Clock Id conflict on unload: $id is registered to another provider"
+ )
+ continue
+ }
+ info.provider = null
+ onUnloaded(id)
+ }
+
+ verifyLoadedProviders()
+ }
+
+ override fun onPluginDetached(manager: PluginLifecycleManager<ClockProviderPlugin>) {
+ val removed = mutableListOf<ClockId>()
+ availableClocks.entries.removeAll {
+ if (it.value.manager != manager) {
+ return@removeAll false
+ }
+
+ removed.add(it.key)
+ return@removeAll true
+ }
+
+ removed.forEach(::onDisconnected)
+ if (removed.size > 0) {
+ triggerOnAvailableClocksChanged()
+ }
+ }
}
private val userSwitchObserver =
@@ -96,7 +174,8 @@ open class ClockRegistry(
protected set(value) {
if (field != value) {
field = value
- scope.launch(mainDispatcher) { onClockChanged { it.onCurrentClockChanged() } }
+ verifyLoadedProviders()
+ triggerOnCurrentClockChanged()
}
}
@@ -168,9 +247,36 @@ open class ClockRegistry(
Assert.isNotMainThread()
}
- private fun onClockChanged(func: (ClockChangeListener) -> Unit) {
- assertMainThread()
- clockChangeListeners.forEach(func)
+ private var isClockChanged = AtomicBoolean(false)
+ private fun triggerOnCurrentClockChanged() {
+ val shouldSchedule = isClockChanged.compareAndSet(false, true)
+ if (!shouldSchedule) {
+ return
+ }
+
+ android.util.Log.e("HAWK", "triggerOnCurrentClockChanged")
+ scope.launch(mainDispatcher) {
+ assertMainThread()
+ android.util.Log.e("HAWK", "isClockChanged")
+ isClockChanged.set(false)
+ clockChangeListeners.forEach { it.onCurrentClockChanged() }
+ }
+ }
+
+ private var isClockListChanged = AtomicBoolean(false)
+ private fun triggerOnAvailableClocksChanged() {
+ val shouldSchedule = isClockListChanged.compareAndSet(false, true)
+ if (!shouldSchedule) {
+ return
+ }
+
+ android.util.Log.e("HAWK", "triggerOnAvailableClocksChanged")
+ scope.launch(mainDispatcher) {
+ assertMainThread()
+ android.util.Log.e("HAWK", "isClockListChanged")
+ isClockListChanged.set(false)
+ clockChangeListeners.forEach { it.onAvailableClocksChanged() }
+ }
}
public fun mutateSetting(mutator: (ClockSettings) -> ClockSettings) {
@@ -190,7 +296,12 @@ open class ClockRegistry(
}
init {
- connectClocks(defaultClockProvider)
+ // Register default clock designs
+ for (clock in defaultClockProvider.getClocks()) {
+ availableClocks[clock.clockId] = ClockInfo(clock, defaultClockProvider, null)
+ }
+
+ // Something has gone terribly wrong if the default clock isn't present
if (!availableClocks.containsKey(DEFAULT_CLOCK_ID)) {
throw IllegalArgumentException(
"$defaultClockProvider did not register clock at $DEFAULT_CLOCK_ID"
@@ -244,59 +355,87 @@ open class ClockRegistry(
}
}
- private fun connectClocks(provider: ClockProvider) {
- var isAvailableChanged = false
- val currentId = currentClockId
- for (clock in provider.getClocks()) {
- val id = clock.clockId
- val current = availableClocks[id]
- if (current != null) {
- Log.e(
- TAG,
- "Clock Id conflict: $id is registered by both " +
- "${provider::class.simpleName} and ${current.provider::class.simpleName}"
- )
- continue
- }
+ private var isVerifying = AtomicBoolean(false)
+ private fun verifyLoadedProviders() {
+ val shouldSchedule = isVerifying.compareAndSet(false, true)
+ if (!shouldSchedule) {
+ return
+ }
- availableClocks[id] = ClockInfo(clock, provider)
- isAvailableChanged = true
- if (DEBUG) {
- Log.i(TAG, "Added ${clock.clockId}")
+ scope.launch(bgDispatcher) {
+ if (keepAllLoaded) {
+ // Enforce that all plugins are loaded if requested
+ for ((_, info) in availableClocks) {
+ info.manager?.loadPlugin()
+ }
+ isVerifying.set(false)
+ return@launch
}
- if (currentId == id) {
- if (DEBUG) {
- Log.i(TAG, "Current clock ($currentId) was connected")
+ val currentClock = availableClocks[currentClockId]
+ if (currentClock == null) {
+ // Current Clock missing, load no plugins and use default
+ for ((_, info) in availableClocks) {
+ info.manager?.unloadPlugin()
}
- onClockChanged { it.onCurrentClockChanged() }
+ isVerifying.set(false)
+ return@launch
}
- }
- if (isAvailableChanged) {
- onClockChanged { it.onAvailableClocksChanged() }
+ val currentManager = currentClock.manager
+ currentManager?.loadPlugin()
+
+ for ((_, info) in availableClocks) {
+ val manager = info.manager
+ if (manager != null && manager.isLoaded && currentManager != manager) {
+ manager.unloadPlugin()
+ }
+ }
+ isVerifying.set(false)
}
}
- private fun disconnectClocks(provider: ClockProvider) {
- var isAvailableChanged = false
- val currentId = currentClockId
- for (clock in provider.getClocks()) {
- availableClocks.remove(clock.clockId)
- isAvailableChanged = true
+ private fun onConnected(clockId: ClockId) {
+ if (DEBUG) {
+ Log.i(TAG, "Connected $clockId")
+ }
+ if (currentClockId == clockId) {
if (DEBUG) {
- Log.i(TAG, "Removed ${clock.clockId}")
+ Log.i(TAG, "Current clock ($clockId) was connected")
}
+ }
+ }
- if (currentId == clock.clockId) {
- Log.w(TAG, "Current clock ($currentId) was disconnected")
- onClockChanged { it.onCurrentClockChanged() }
- }
+ private fun onLoaded(clockId: ClockId) {
+ if (DEBUG) {
+ Log.i(TAG, "Loaded $clockId")
+ }
+
+ if (currentClockId == clockId) {
+ Log.i(TAG, "Current clock ($clockId) was loaded")
+ triggerOnCurrentClockChanged()
+ }
+ }
+
+ private fun onUnloaded(clockId: ClockId) {
+ if (DEBUG) {
+ Log.i(TAG, "Unloaded $clockId")
+ }
+
+ if (currentClockId == clockId) {
+ Log.w(TAG, "Current clock ($clockId) was unloaded")
+ triggerOnCurrentClockChanged()
+ }
+ }
+
+ private fun onDisconnected(clockId: ClockId) {
+ if (DEBUG) {
+ Log.i(TAG, "Disconnected $clockId")
}
- if (isAvailableChanged) {
- onClockChanged { it.onAvailableClocksChanged() }
+ if (currentClockId == clockId) {
+ Log.w(TAG, "Current clock ($clockId) was disconnected")
}
}
@@ -345,6 +484,7 @@ open class ClockRegistry(
private data class ClockInfo(
val metadata: ClockMetadata,
- val provider: ClockProvider,
+ var provider: ClockProvider?,
+ val manager: PluginLifecycleManager<ClockProviderPlugin>?,
)
}
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java
new file mode 100644
index 000000000000..cc6a46fa7d6b
--- /dev/null
+++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.plugins;
+
+/**
+ * Provides the ability for consumers to control plugin lifecycle.
+ *
+ * @param <T> is the target plugin type
+ */
+public interface PluginLifecycleManager<T extends Plugin> {
+ /** Returns the currently loaded plugin instance (if plugin is loaded) */
+ T getPlugin();
+
+ /** returns true if the plugin is currently loaded */
+ default boolean isLoaded() {
+ return getPlugin() != null;
+ }
+
+ /**
+ * Loads and creates the plugin instance if it does not exist.
+ *
+ * This will trigger {@link PluginListener#onPluginLoaded} with the new instance if it did not
+ * already exist.
+ */
+ void loadPlugin();
+
+ /**
+ * Unloads and destroys the plugin instance if it exists.
+ *
+ * This will trigger {@link PluginListener#onPluginUnloaded} if a concrete plugin instance
+ * existed when this call was made.
+ */
+ void unloadPlugin();
+}
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginListener.java b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginListener.java
index b488d2a84baa..c5f503216101 100644
--- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginListener.java
+++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginListener.java
@@ -17,7 +17,32 @@ package com.android.systemui.plugins;
import android.content.Context;
/**
- * Interface for listening to plugins being connected.
+ * Interface for listening to plugins being connected and disconnected.
+ *
+ * The call order for a plugin is
+ * 1) {@link #onPluginAttached}
+ * Called when a new plugin is added to the device, or an existing plugin was replaced by
+ * the package manager. Will only be called once per package manager event. If multiple
+ * non-conflicting packages which have the same plugin interface are installed on the
+ * device, then this method can be called multiple times with different instances of
+ * {@link PluginLifecycleManager} (as long as `allowMultiple` was set to true when the
+ * listener was registered with {@link PluginManager#addPluginListener}).
+ * 2) {@link #onPluginLoaded}
+ * Called whenever a new instance of the plugin object is created and ready for use. Can be
+ * called multiple times per {@link PluginLifecycleManager}, but will always pass a newly
+ * created plugin object. {@link #onPluginUnloaded} with the previous plugin object will
+ * be called before another call to {@link #onPluginLoaded} is made. This method will be
+ * called once automatically after {@link #onPluginAttached}. Besides the initial call,
+ * {@link #onPluginLoaded} will occur due to {@link PluginLifecycleManager#loadPlugin}.
+ * 3) {@link #onPluginUnloaded}
+ * Called when a request to unload the plugin has been received. This can be triggered from
+ * a related call to {@link PluginLifecycleManager#unloadPlugin} or for any reason that
+ * {@link #onPluginDetached} would be triggered.
+ * 4) {@link #onPluginDetached}
+ * Called when the package is removed from the device, disabled, or replaced due to an
+ * external trigger. These are events from the android package manager.
+ *
+ * @param <T> is the target plugin type
*/
public interface PluginListener<T extends Plugin> {
/**
@@ -25,14 +50,69 @@ public interface PluginListener<T extends Plugin> {
* This may be called multiple times if multiple plugins are allowed.
* It may also be called in the future if the plugin package changes
* and needs to be reloaded.
+ *
+ * @deprecated Migrate to {@link #onPluginLoaded} or {@link #onPluginAttached}
+ */
+ @Deprecated
+ default void onPluginConnected(T plugin, Context pluginContext) {
+ // Optional
+ }
+
+ /**
+ * Called when the plugin is first attached to the host application. {@link #onPluginLoaded}
+ * will be automatically called as well when first attached. This may be called multiple times
+ * if multiple plugins are allowed. It may also be called in the future if the plugin package
+ * changes and needs to be reloaded. Each call to {@link #onPluginAttached} will provide a new
+ * or different {@link PluginLifecycleManager}.
*/
- void onPluginConnected(T plugin, Context pluginContext);
+ default void onPluginAttached(PluginLifecycleManager<T> manager) {
+ // Optional
+ }
/**
* Called when a plugin has been uninstalled/updated and should be removed
* from use.
+ *
+ * @deprecated Migrate to {@link #onPluginDetached} or {@link #onPluginUnloaded}
*/
+ @Deprecated
default void onPluginDisconnected(T plugin) {
// Optional.
}
-}
+
+ /**
+ * Called when the plugin has been detached from the host application. Implementers should no
+ * longer attempt to reload it via this {@link PluginLifecycleManager}. If the package was
+ * updated and not removed, then {@link #onPluginAttached} will be called again when the updated
+ * package is available.
+ */
+ default void onPluginDetached(PluginLifecycleManager<T> manager) {
+ // Optional.
+ }
+
+ /**
+ * Called when the plugin is loaded into the host's process and is available for use. This can
+ * happen several times if clients are using {@link PluginLifecycleManager} to manipulate a
+ * plugin's load state. Each call to {@link #onPluginLoaded} will have a matched call to
+ * {@link #onPluginUnloaded} when that plugin object should no longer be used.
+ */
+ default void onPluginLoaded(
+ T plugin,
+ Context pluginContext,
+ PluginLifecycleManager<T> manager
+ ) {
+ // Optional, default to deprecated version
+ onPluginConnected(plugin, pluginContext);
+ }
+
+ /**
+ * Called when the plugin should no longer be used. Listeners should clean up all references to
+ * the relevant plugin so that it can be garbage collected. If the plugin object is required in
+ * the future a call can be made to {@link PluginLifecycleManager#loadPlugin} to create a new
+ * plugin object and trigger {@link #onPluginLoaded}.
+ */
+ default void onPluginUnloaded(T plugin, PluginLifecycleManager<T> manager) {
+ // Optional, default to deprecated version
+ onPluginDisconnected(plugin);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 9b2f0ac364da..79948da978d7 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -311,7 +311,7 @@
android:clickable="false"
android:focusable="false"
android:ellipsize="end"
- android:maxLines="3"
+ android:maxLines="4"
android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
</com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
@@ -364,7 +364,7 @@
android:clickable="false"
android:focusable="false"
android:ellipsize="end"
- android:maxLines="3"
+ android:maxLines="4"
android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
</com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 6354752e1b22..763930db1d55 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -30,9 +30,6 @@
<bool name="flag_charging_ripple">false</bool>
- <!-- Whether to show chipbar UI whenever the device is unlocked by ActiveUnlock. -->
- <bool name="flag_active_unlock_chipbar">true</bool>
-
<!-- Whether the user switcher chip shows in the status bar. When true, the multi user
avatar will no longer show on the lockscreen -->
<bool name="flag_user_switcher_chip">false</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ebf0f8ecd48c..2aa912ce250d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2877,7 +2877,7 @@
<string name="manage_users">Manage users</string>
<!-- Toast shown when a notification does not support dragging to split [CHAR LIMIT=NONE] -->
- <string name="drag_split_not_supported">This notification does not support dragging to Splitscreen.</string>
+ <string name="drag_split_not_supported">This notification does not support dragging to split screen</string>
<!-- Content description for the Wi-Fi off icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
<string name="dream_overlay_status_bar_wifi_off">Wi\u2011Fi unavailable</string>
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt
index 97665145ce76..dedf0a7a742d 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt
@@ -53,6 +53,7 @@ import kotlinx.coroutines.runBlocking
fun View.captureToBitmap(window: Window? = null): ListenableFuture<Bitmap> {
val bitmapFuture: ResolvableFuture<Bitmap> = ResolvableFuture.create()
val mainExecutor = HandlerExecutor(Handler(Looper.getMainLooper()))
+ val isRobolectric = if (Build.FINGERPRINT.contains("robolectric")) true else false
// disable drawing again if necessary once work is complete
if (!HardwareRendererCompat.isDrawingEnabled()) {
@@ -61,8 +62,12 @@ fun View.captureToBitmap(window: Window? = null): ListenableFuture<Bitmap> {
}
mainExecutor.execute {
- val forceRedrawFuture = forceRedraw()
- forceRedrawFuture.addListener({ generateBitmap(bitmapFuture, window) }, mainExecutor)
+ if (isRobolectric) {
+ generateBitmap(bitmapFuture)
+ } else {
+ val forceRedrawFuture = forceRedraw()
+ forceRedrawFuture.addListener({ generateBitmap(bitmapFuture, window) }, mainExecutor)
+ }
}
return bitmapFuture
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
index 2d47356f2ce1..f96d1e3d7fef 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
@@ -19,6 +19,7 @@ package com.android.systemui.testing.screenshot
import android.app.Activity
import android.app.Dialog
import android.graphics.Bitmap
+import android.os.Build
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams
@@ -26,6 +27,7 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import androidx.activity.ComponentActivity
import androidx.test.ext.junit.rules.ActivityScenarioRule
+import java.util.concurrent.TimeUnit
import org.junit.Assert.assertEquals
import org.junit.rules.RuleChain
import org.junit.rules.TestRule
@@ -54,14 +56,14 @@ open class ViewScreenshotTestRule(
)
)
private val activityRule = ActivityScenarioRule(ScreenshotActivity::class.java)
- private val delegateRule =
- RuleChain.outerRule(colorsRule)
- .around(deviceEmulationRule)
- .around(screenshotRule)
- .around(activityRule)
+ private val roboRule =
+ RuleChain.outerRule(deviceEmulationRule).around(screenshotRule).around(activityRule)
+ private val delegateRule = RuleChain.outerRule(colorsRule).around(roboRule)
+ private val isRobolectric = if (Build.FINGERPRINT.contains("robolectric")) true else false
override fun apply(base: Statement, description: Description): Statement {
- return delegateRule.apply(base, description)
+ val ruleToApply = if (isRobolectric) roboRule else delegateRule
+ return ruleToApply.apply(base, description)
}
protected fun takeScreenshot(
@@ -94,7 +96,12 @@ open class ViewScreenshotTestRule(
contentView = content.getChildAt(0)
}
- return contentView?.toBitmap() ?: error("contentView is null")
+ return if (isRobolectric) {
+ contentView?.captureToBitmap()?.get(10, TimeUnit.SECONDS)
+ ?: error("timeout while trying to capture view to bitmap")
+ } else {
+ contentView?.toBitmap() ?: error("contentView is null")
+ }
}
/**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java
index cc3d7a8931b0..3d05542116e0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java
@@ -210,12 +210,12 @@ public class PluginActionManager<T extends Plugin> {
private void onPluginConnected(PluginInstance<T> pluginInstance) {
if (DEBUG) Log.d(TAG, "onPluginConnected");
PluginPrefs.setHasPlugins(mContext);
- pluginInstance.onCreate(mContext, mListener);
+ pluginInstance.onCreate();
}
private void onPluginDisconnected(PluginInstance<T> pluginInstance) {
if (DEBUG) Log.d(TAG, "onPluginDisconnected");
- pluginInstance.onDestroy(mListener);
+ pluginInstance.onDestroy();
}
private void queryAll() {
@@ -312,7 +312,7 @@ public class PluginActionManager<T extends Plugin> {
try {
return mPluginInstanceFactory.create(
mContext, appInfo, component,
- mPluginClass);
+ mPluginClass, mListener);
} catch (InvalidVersionException e) {
reportInvalidVersion(component, component.getClassName(), e);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
index 2f84602089e0..016d573930e8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
@@ -21,13 +21,16 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginFragment;
+import com.android.systemui.plugins.PluginLifecycleManager;
import com.android.systemui.plugins.PluginListener;
import dalvik.system.PathClassLoader;
@@ -35,7 +38,7 @@ import dalvik.system.PathClassLoader;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
+import java.util.function.Supplier;
/**
* Contains a single instantiation of a Plugin.
@@ -45,42 +48,102 @@ import java.util.Map;
*
* @param <T> The type of plugin that this contains.
*/
-public class PluginInstance<T extends Plugin> {
+public class PluginInstance<T extends Plugin> implements PluginLifecycleManager {
private static final String TAG = "PluginInstance";
- private static final Map<String, ClassLoader> sClassLoaders = new ArrayMap<>();
- private final Context mPluginContext;
- private final VersionInfo mVersionInfo;
+ private final Context mAppContext;
+ private final PluginListener<T> mListener;
private final ComponentName mComponentName;
- private final T mPlugin;
+ private final PluginFactory<T> mPluginFactory;
+
+ private Context mPluginContext;
+ private T mPlugin;
/** */
- public PluginInstance(ComponentName componentName, T plugin, Context pluginContext,
- VersionInfo versionInfo) {
+ public PluginInstance(
+ Context appContext,
+ PluginListener<T> listener,
+ ComponentName componentName,
+ PluginFactory<T> pluginFactory,
+ @Nullable T plugin) {
+ mAppContext = appContext;
+ mListener = listener;
mComponentName = componentName;
+ mPluginFactory = pluginFactory;
mPlugin = plugin;
- mPluginContext = pluginContext;
- mVersionInfo = versionInfo;
+
+ if (mPlugin != null) {
+ mPluginContext = mPluginFactory.createPluginContext();
+ }
}
/** Alerts listener and plugin that the plugin has been created. */
- public void onCreate(Context appContext, PluginListener<T> listener) {
+ public void onCreate() {
+ mListener.onPluginAttached(this);
+ if (mPlugin == null) {
+ loadPlugin();
+ } else {
+ if (!(mPlugin instanceof PluginFragment)) {
+ // Only call onCreate for plugins that aren't fragments, as fragments
+ // will get the onCreate as part of the fragment lifecycle.
+ mPlugin.onCreate(mAppContext, mPluginContext);
+ }
+ mListener.onPluginLoaded(mPlugin, mPluginContext, this);
+ }
+ }
+
+ /** Alerts listener and plugin that the plugin is being shutdown. */
+ public void onDestroy() {
+ unloadPlugin();
+ mListener.onPluginDetached(this);
+ }
+
+ /** Returns the current plugin instance (if it is loaded). */
+ @Nullable
+ public T getPlugin() {
+ return mPlugin;
+ }
+
+ /**
+ * Loads and creates the plugin if it does not exist.
+ */
+ public void loadPlugin() {
+ if (mPlugin != null) {
+ return;
+ }
+
+ mPlugin = mPluginFactory.createPlugin();
+ mPluginContext = mPluginFactory.createPluginContext();
+ if (mPlugin == null || mPluginContext == null) {
+ return;
+ }
+
if (!(mPlugin instanceof PluginFragment)) {
// Only call onCreate for plugins that aren't fragments, as fragments
// will get the onCreate as part of the fragment lifecycle.
- mPlugin.onCreate(appContext, mPluginContext);
+ mPlugin.onCreate(mAppContext, mPluginContext);
}
- listener.onPluginConnected(mPlugin, mPluginContext);
+ mListener.onPluginLoaded(mPlugin, mPluginContext, this);
}
- /** Alerts listener and plugin that the plugin is being shutdown. */
- public void onDestroy(PluginListener<T> listener) {
- listener.onPluginDisconnected(mPlugin);
+ /**
+ * Unloads and destroys the current plugin instance if it exists.
+ *
+ * This will free the associated memory if there are not other references.
+ */
+ public void unloadPlugin() {
+ if (mPlugin == null) {
+ return;
+ }
+
+ mListener.onPluginUnloaded(mPlugin, this);
if (!(mPlugin instanceof PluginFragment)) {
// Only call onDestroy for plugins that aren't fragments, as fragments
// will get the onDestroy as part of the fragment lifecycle.
mPlugin.onDestroy();
}
+ mPlugin = null;
+ mPluginContext = null;
}
/**
@@ -89,7 +152,7 @@ public class PluginInstance<T extends Plugin> {
* It does this by string comparison of the class names.
**/
public boolean containsPluginClass(Class pluginClass) {
- return mPlugin.getClass().getName().equals(pluginClass.getName());
+ return mComponentName.getClassName().equals(pluginClass.getName());
}
public ComponentName getComponentName() {
@@ -101,7 +164,7 @@ public class PluginInstance<T extends Plugin> {
}
public VersionInfo getVersionInfo() {
- return mVersionInfo;
+ return mPluginFactory.checkVersion(mPlugin);
}
@VisibleForTesting
@@ -134,21 +197,20 @@ public class PluginInstance<T extends Plugin> {
Context context,
ApplicationInfo appInfo,
ComponentName componentName,
- Class<T> pluginClass)
+ Class<T> pluginClass,
+ PluginListener<T> listener)
throws PackageManager.NameNotFoundException, ClassNotFoundException,
InstantiationException, IllegalAccessException {
- ClassLoader classLoader = getClassLoader(appInfo, mBaseClassLoader);
- Context pluginContext = new PluginActionManager.PluginContextWrapper(
- context.createApplicationContext(appInfo, 0), classLoader);
- Class<T> instanceClass = (Class<T>) Class.forName(
- componentName.getClassName(), true, classLoader);
+ PluginFactory<T> pluginFactory = new PluginFactory<T>(
+ context, mInstanceFactory, appInfo, componentName, mVersionChecker, pluginClass,
+ () -> getClassLoader(appInfo, mBaseClassLoader));
// TODO: Only create the plugin before version check if we need it for
// legacy version check.
- T instance = (T) mInstanceFactory.create(instanceClass);
- VersionInfo version = mVersionChecker.checkVersion(
- instanceClass, pluginClass, instance);
- return new PluginInstance<T>(componentName, instance, pluginContext, version);
+ T instance = pluginFactory.createPlugin();
+ pluginFactory.checkVersion(instance);
+ return new PluginInstance<T>(
+ context, listener, componentName, pluginFactory, instance);
}
private boolean isPluginPackagePrivileged(String packageName) {
@@ -179,9 +241,6 @@ public class PluginInstance<T extends Plugin> {
+ appInfo.sourceDir + ", pkg: " + appInfo.packageName);
return null;
}
- if (sClassLoaders.containsKey(appInfo.packageName)) {
- return sClassLoaders.get(appInfo.packageName);
- }
List<String> zipPaths = new ArrayList<>();
List<String> libPaths = new ArrayList<>();
@@ -190,13 +249,20 @@ public class PluginInstance<T extends Plugin> {
TextUtils.join(File.pathSeparator, zipPaths),
TextUtils.join(File.pathSeparator, libPaths),
getParentClassLoader(baseClassLoader));
- sClassLoaders.put(appInfo.packageName, classLoader);
return classLoader;
}
}
/** Class that compares a plugin class against an implementation for version matching. */
- public static class VersionChecker {
+ public interface VersionChecker {
+ /** Compares two plugin classes. */
+ <T extends Plugin> VersionInfo checkVersion(
+ Class<T> instanceClass, Class<T> pluginClass, Plugin plugin);
+ }
+
+ /** Class that compares a plugin class against an implementation for version matching. */
+ public static class VersionCheckerImpl implements VersionChecker {
+ @Override
/** Compares two plugin classes. */
public <T extends Plugin> VersionInfo checkVersion(
Class<T> instanceClass, Class<T> pluginClass, Plugin plugin) {
@@ -204,7 +270,7 @@ public class PluginInstance<T extends Plugin> {
VersionInfo instanceVersion = new VersionInfo().addClass(instanceClass);
if (instanceVersion.hasVersionInfo()) {
pluginVersion.checkVersion(instanceVersion);
- } else {
+ } else if (plugin != null) {
int fallbackVersion = plugin.getVersion();
if (fallbackVersion != pluginVersion.getDefaultVersion()) {
throw new VersionInfo.InvalidVersionException("Invalid legacy version", false);
@@ -225,4 +291,74 @@ public class PluginInstance<T extends Plugin> {
return (T) cls.newInstance();
}
}
+
+ /**
+ * Instanced wrapper of InstanceFactory
+ *
+ * @param <T> is the type of the plugin object to be built
+ **/
+ public static class PluginFactory<T extends Plugin> {
+ private final Context mContext;
+ private final InstanceFactory<?> mInstanceFactory;
+ private final ApplicationInfo mAppInfo;
+ private final ComponentName mComponentName;
+ private final VersionChecker mVersionChecker;
+ private final Class<T> mPluginClass;
+ private final Supplier<ClassLoader> mClassLoaderFactory;
+
+ public PluginFactory(
+ Context context,
+ InstanceFactory<?> instanceFactory,
+ ApplicationInfo appInfo,
+ ComponentName componentName,
+ VersionChecker versionChecker,
+ Class<T> pluginClass,
+ Supplier<ClassLoader> classLoaderFactory) {
+ mContext = context;
+ mInstanceFactory = instanceFactory;
+ mAppInfo = appInfo;
+ mComponentName = componentName;
+ mVersionChecker = versionChecker;
+ mPluginClass = pluginClass;
+ mClassLoaderFactory = classLoaderFactory;
+ }
+
+ /** Creates the related plugin object from the factory */
+ public T createPlugin() {
+ try {
+ ClassLoader loader = mClassLoaderFactory.get();
+ Class<T> instanceClass = (Class<T>) Class.forName(
+ mComponentName.getClassName(), true, loader);
+ return (T) mInstanceFactory.create(instanceClass);
+ } catch (ClassNotFoundException ex) {
+ Log.e(TAG, "Failed to load plugin", ex);
+ } catch (IllegalAccessException ex) {
+ Log.e(TAG, "Failed to load plugin", ex);
+ } catch (InstantiationException ex) {
+ Log.e(TAG, "Failed to load plugin", ex);
+ }
+ return null;
+ }
+
+ /** Creates a context wrapper for the plugin */
+ public Context createPluginContext() {
+ try {
+ ClassLoader loader = mClassLoaderFactory.get();
+ return new PluginActionManager.PluginContextWrapper(
+ mContext.createApplicationContext(mAppInfo, 0), loader);
+ } catch (NameNotFoundException ex) {
+ Log.e(TAG, "Failed to create plugin context", ex);
+ }
+ return null;
+ }
+
+ /** Check Version and create VersionInfo for instance */
+ public VersionInfo checkVersion(T instance) {
+ if (instance == null) {
+ instance = createPlugin();
+ }
+ return mVersionChecker.checkVersion(
+ (Class<T>) instance.getClass(), mPluginClass, instance);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
index b1a83fbda7de..6e98a1805d62 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
@@ -60,7 +60,9 @@ public abstract class ClockRegistryModule {
featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS),
/* handleAllUsers= */ true,
new DefaultClockProvider(context, layoutInflater, resources),
- context.getString(R.string.lockscreen_clock_id_fallback));
+ context.getString(R.string.lockscreen_clock_id_fallback),
+ /* keepAllLoaded = */ false,
+ /* subTag = */ "System");
registry.registerListeners();
return registry;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index a7b6e6ae6d40..13bb6d345dbd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -658,7 +658,9 @@ public abstract class AuthBiometricView extends LinearLayout {
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mIconController.onConfigurationChanged(newConfig);
- updateState(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_STATE));
+ if (mSavedState != null) {
+ updateState(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_STATE));
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 661b2b6daf64..a80d28d7877f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -162,12 +162,6 @@ object Flags {
val CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES =
releasedFlag(216, "customizable_lock_screen_quick_affordances")
- /** Shows chipbar UI whenever the device is unlocked by ActiveUnlock (watch). */
- // TODO(b/256513609): Tracking Bug
- @JvmField
- val ACTIVE_UNLOCK_CHIPBAR =
- resourceBooleanFlag(217, R.bool.flag_active_unlock_chipbar, "active_unlock_chipbar")
-
/**
* Migrates control of the LightRevealScrim's reveal effect and amount from legacy code to the
* new KeyguardTransitionRepository.
@@ -242,12 +236,21 @@ object Flags {
// TODO(b/270223352): Tracking Bug
@JvmField
- val HIDE_SMARTSPACE_ON_DREAM_OVERLAY = unreleasedFlag(404, "hide_smartspace_on_dream_overlay")
+ val HIDE_SMARTSPACE_ON_DREAM_OVERLAY =
+ unreleasedFlag(
+ 404,
+ "hide_smartspace_on_dream_overlay",
+ teamfood = true
+ )
// TODO(b/271460958): Tracking Bug
@JvmField
- val SHOW_WEATHER_COMPLICATION_ON_DREAM_OVERLAY = unreleasedFlag(405,
- "show_weather_complication_on_dream_overlay")
+ val SHOW_WEATHER_COMPLICATION_ON_DREAM_OVERLAY =
+ unreleasedFlag(
+ 405,
+ "show_weather_complication_on_dream_overlay",
+ teamfood = true
+ )
// 500 - quick settings
@@ -284,8 +287,7 @@ object Flags {
/** Enables new QS Edit Mode visual refresh */
// TODO(b/269787742): Tracking Bug
@JvmField
- val ENABLE_NEW_QS_EDIT_MODE =
- unreleasedFlag(510, "enable_new_qs_edit_mode", teamfood = false)
+ val ENABLE_NEW_QS_EDIT_MODE = unreleasedFlag(510, "enable_new_qs_edit_mode", teamfood = false)
// 600- status bar
@@ -668,8 +670,7 @@ object Flags {
// 2600 - keyboard
// TODO(b/259352579): Tracking Bug
- @JvmField val SHORTCUT_LIST_SEARCH_LAYOUT =
- unreleasedFlag(2600, "shortcut_list_search_layout", teamfood = true)
+ @JvmField val SHORTCUT_LIST_SEARCH_LAYOUT = releasedFlag(2600, "shortcut_list_search_layout")
// TODO(b/259428678): Tracking Bug
@JvmField
@@ -680,4 +681,9 @@ object Flags {
@JvmField
val LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION =
unreleasedFlag(2602, "large_shade_granular_alpha_interpolation", teamfood = true)
+
+ // TODO(b/272805037): Tracking Bug
+ @JvmField
+ val ADVANCED_VPN_ENABLED = unreleasedFlag(2800, name = "AdvancedVpn__enable_feature",
+ namespace = "vpn", teamfood = false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
index 95f14190537f..fbf1a0e46ce3 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
@@ -73,7 +73,7 @@ public abstract class PluginsModule {
return new PluginInstance.Factory(
PluginModule.class.getClassLoader(),
new PluginInstance.InstanceFactory<>(),
- new PluginInstance.VersionChecker(),
+ new PluginInstance.VersionCheckerImpl(),
privilegedPlugins,
isDebug);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index baa812c63aa7..584d27f84ceb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -635,7 +635,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
&& mLastKeyguardAndExpanded == onKeyguardAndExpanded
&& mLastViewHeight == currentHeight
&& mLastHeaderTranslation == headerTranslation
- && mSquishinessFraction == squishinessFraction) {
+ && mSquishinessFraction == squishinessFraction
+ && mLastPanelFraction == panelExpansionFraction) {
return;
}
mLastHeaderTranslation = headerTranslation;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
index a71e6ddb6abd..9ece72d2ca7f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
@@ -26,6 +26,7 @@ import com.android.systemui.R;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTileView;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.util.leak.GarbageMonitor;
import java.util.ArrayList;
@@ -33,7 +34,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
-public interface QSHost {
+public interface QSHost extends PanelInteractor {
String TILES_SETTING = Settings.Secure.QS_TILES;
int POSITION_AT_END = -1;
@@ -57,9 +58,6 @@ public interface QSHost {
}
void warn(String message, Throwable t);
- void collapsePanels();
- void forceCollapsePanels();
- void openPanels();
Context getContext();
Context getUserContext();
int getUserId();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.kt b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.kt
new file mode 100644
index 000000000000..958fa71b1fd8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.kt
@@ -0,0 +1,50 @@
+/*
+ * 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
+ */
+
+package com.android.systemui.qs.dagger
+
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.qs.QSHost
+import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractorImpl
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+
+@Module
+interface QSHostModule {
+
+ @Binds fun provideQsHost(controllerImpl: QSTileHost): QSHost
+
+ @Module
+ companion object {
+ @Provides
+ @JvmStatic
+ fun providePanelInteractor(
+ featureFlags: FeatureFlags,
+ qsHost: QSHost,
+ panelInteractorImpl: PanelInteractorImpl
+ ): PanelInteractor {
+ return if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) {
+ panelInteractorImpl
+ } else {
+ qsHost
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 431d6e847207..cfe93132c044 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -27,7 +27,6 @@ import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.media.dagger.MediaModule;
import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.qs.external.QSExternalModule;
import com.android.systemui.qs.tileimpl.QSTileImpl;
@@ -45,7 +44,6 @@ import java.util.Map;
import javax.inject.Named;
-import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.Multibinds;
@@ -54,7 +52,13 @@ import dagger.multibindings.Multibinds;
* Module for QS dependencies
*/
@Module(subcomponents = {QSFragmentComponent.class},
- includes = {MediaModule.class, QSExternalModule.class, QSFlagsModule.class})
+ includes = {
+ MediaModule.class,
+ QSExternalModule.class,
+ QSFlagsModule.class,
+ QSHostModule.class
+ }
+)
public interface QSModule {
/** A map of internal QS tiles. Ensures that this can be injected even if
@@ -100,8 +104,4 @@ public interface QSModule {
manager.init();
return manager;
}
-
- /** */
- @Binds
- QSHost provideQsHost(QSTileHost controllerImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index adc71657e680..2083cc7b167e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -40,6 +40,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -74,6 +75,7 @@ public class TileServices extends IQSService.Stub {
private final CommandQueue mCommandQueue;
private final UserTracker mUserTracker;
private final StatusBarIconController mStatusBarIconController;
+ private final PanelInteractor mPanelInteractor;
private int mMaxBound = DEFAULT_MAX_BOUND;
@@ -85,7 +87,8 @@ public class TileServices extends IQSService.Stub {
UserTracker userTracker,
KeyguardStateController keyguardStateController,
CommandQueue commandQueue,
- StatusBarIconController statusBarIconController) {
+ StatusBarIconController statusBarIconController,
+ PanelInteractor panelInteractor) {
mHost = host;
mKeyguardStateController = keyguardStateController;
mContext = mHost.getContext();
@@ -96,6 +99,7 @@ public class TileServices extends IQSService.Stub {
mCommandQueue = commandQueue;
mStatusBarIconController = statusBarIconController;
mCommandQueue.addCallback(mRequestListeningCallback);
+ mPanelInteractor = panelInteractor;
}
public Context getContext() {
@@ -255,7 +259,7 @@ public class TileServices extends IQSService.Stub {
if (customTile != null) {
verifyCaller(customTile);
customTile.onDialogShown();
- mHost.forceCollapsePanels();
+ mPanelInteractor.forceCollapsePanels();
Objects.requireNonNull(mServices.get(customTile)).setShowingDialog(true);
}
}
@@ -275,7 +279,7 @@ public class TileServices extends IQSService.Stub {
CustomTile customTile = getTileForToken(token);
if (customTile != null) {
verifyCaller(customTile);
- mHost.forceCollapsePanels();
+ mPanelInteractor.forceCollapsePanels();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractor.kt
new file mode 100644
index 000000000000..260caa767a5e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 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.qs.pipeline.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import java.util.Optional
+import javax.inject.Inject
+
+/** Encapsulates business logic for interacting with the QS panel. */
+interface PanelInteractor {
+
+ /** Collapse the shade */
+ fun collapsePanels()
+
+ /** Collapse the shade forcefully, skipping some animations. */
+ fun forceCollapsePanels()
+
+ /** Open the Quick Settings panel */
+ fun openPanels()
+}
+
+@SysUISingleton
+class PanelInteractorImpl
+@Inject
+constructor(
+ private val centralSurfaces: Optional<CentralSurfaces>,
+) : PanelInteractor {
+ override fun collapsePanels() {
+ centralSurfaces.ifPresent { it.postAnimateCollapsePanels() }
+ }
+
+ override fun forceCollapsePanels() {
+ centralSurfaces.ifPresent { it.postAnimateForceCollapsePanels() }
+ }
+
+ override fun openPanels() {
+ centralSurfaces.ifPresent { it.postAnimateOpenPanels() }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 89d402a3af5a..27f58269722a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -38,6 +38,7 @@ import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.LocationController;
@@ -52,6 +53,7 @@ public class LocationTile extends QSTileImpl<BooleanState> {
private final LocationController mController;
private final KeyguardStateController mKeyguard;
+ private final PanelInteractor mPanelInteractor;
private final Callback mCallback = new Callback();
@Inject
@@ -65,12 +67,14 @@ public class LocationTile extends QSTileImpl<BooleanState> {
ActivityStarter activityStarter,
QSLogger qsLogger,
LocationController locationController,
- KeyguardStateController keyguardStateController
+ KeyguardStateController keyguardStateController,
+ PanelInteractor panelInteractor
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mController = locationController;
mKeyguard = keyguardStateController;
+ mPanelInteractor = panelInteractor;
mController.observe(this, mCallback);
mKeyguard.observe(this, mCallback);
}
@@ -90,7 +94,7 @@ public class LocationTile extends QSTileImpl<BooleanState> {
if (mKeyguard.isMethodSecure() && mKeyguard.isShowing()) {
mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
final boolean wasEnabled = mState.value;
- mHost.openPanels();
+ mPanelInteractor.openPanels();
mController.setLocationEnabled(!wasEnabled);
});
return;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index 07b50c9a66f6..65592a717565 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -42,6 +42,7 @@ import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
@@ -66,6 +67,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
private final Callback mCallback = new Callback();
private final DialogLaunchAnimator mDialogLaunchAnimator;
private final FeatureFlags mFlags;
+ private final PanelInteractor mPanelInteractor;
private long mMillisUntilFinished = 0;
@@ -83,7 +85,8 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
RecordingController controller,
KeyguardDismissUtil keyguardDismissUtil,
KeyguardStateController keyguardStateController,
- DialogLaunchAnimator dialogLaunchAnimator
+ DialogLaunchAnimator dialogLaunchAnimator,
+ PanelInteractor panelInteractor
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
@@ -93,6 +96,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
mKeyguardDismissUtil = keyguardDismissUtil;
mKeyguardStateController = keyguardStateController;
mDialogLaunchAnimator = dialogLaunchAnimator;
+ mPanelInteractor = panelInteractor;
}
@Override
@@ -171,7 +175,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
// disable the exit animation which looks weird when it happens at the same time as the
// shade collapsing.
mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
- getHost().collapsePanels();
+ mPanelInteractor.collapsePanels();
};
final Dialog dialog = mController.createScreenRecordDialog(mContext, mFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 587c65d44091..30865aa0c45d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -3779,10 +3779,10 @@ public final class NotificationPanelViewController implements Dumpable {
mHeightAnimator.end();
}
}
- mQsController.setShadeExpandedHeight(mExpandedHeight);
- mExpansionDragDownAmountPx = h;
mExpandedFraction = Math.min(1f,
maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
+ mQsController.setShadeExpansion(mExpandedHeight, mExpandedFraction);
+ mExpansionDragDownAmountPx = h;
mAmbientState.setExpansionFraction(mExpandedFraction);
onHeightUpdated(mExpandedHeight);
updatePanelExpansionAndVisibility();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index df8ae50682fc..9f467074d473 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -351,7 +351,6 @@ public class QuickSettingsController {
mFeatureFlags = featureFlags;
mInteractionJankMonitor = interactionJankMonitor;
- mShadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged);
mLockscreenShadeTransitionController.addCallback(new LockscreenShadeTransitionCallback());
}
@@ -878,8 +877,9 @@ public class QuickSettingsController {
mCollapsedOnDown = collapsedOnDown;
}
- void setShadeExpandedHeight(float shadeExpandedHeight) {
- mShadeExpandedHeight = shadeExpandedHeight;
+ void setShadeExpansion(float expandedHeight, float expandedFraction) {
+ mShadeExpandedHeight = expandedHeight;
+ mShadeExpandedFraction = expandedFraction;
}
@VisibleForTesting
@@ -1749,11 +1749,6 @@ public class QuickSettingsController {
return false;
}
- @VisibleForTesting
- void onPanelExpansionChanged(ShadeExpansionChangeEvent event) {
- mShadeExpandedFraction = event.getFraction();
- }
-
/**
* Animate QS closing by flinging it.
* If QS is expanded, it will collapse into QQS and stop.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
index 01e042bf5e15..c920e1ec6604 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -657,25 +657,6 @@ public final class KeyboardShortcutListSearch {
R.string.input_switch_input_language_previous),
KeyEvent.KEYCODE_SPACE,
KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON),
- null))),
- /* Access emoji: Meta + . */
- new ShortcutMultiMappingInfo(
- context.getString(R.string.input_access_emoji),
- null,
- Arrays.asList(
- new ShortcutKeyGroup(new KeyboardShortcutInfo(
- context.getString(R.string.input_access_emoji),
- KeyEvent.KEYCODE_PERIOD,
- KeyEvent.META_META_ON),
- null))),
- /* Access voice typing: Meta + V */
- new ShortcutMultiMappingInfo(
- context.getString(R.string.input_access_voice_typing),
- null,
- Arrays.asList(
- new ShortcutKeyGroup(new KeyboardShortcutInfo(
- context.getString(R.string.input_access_voice_typing),
- KeyEvent.KEYCODE_V, KeyEvent.META_META_ON),
null)))
);
return new KeyboardShortcutMultiMappingGroup(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 33cbf0699bca..a529da54fc4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -68,6 +68,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.CallLayout;
@@ -1671,7 +1672,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
MetricsLogger metricsLogger,
SmartReplyConstants smartReplyConstants,
SmartReplyController smartReplyController,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags,
+ IStatusBarService statusBarService) {
mEntry = entry;
mAppName = appName;
if (mMenuRow == null) {
@@ -1699,7 +1701,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mPeopleNotificationIdentifier,
rivSubcomponentFactory,
smartReplyConstants,
- smartReplyController);
+ smartReplyController,
+ statusBarService);
}
mOnUserInteractionCallback = onUserInteractionCallback;
mBubblesManagerOptional = bubblesManagerOptional;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index e2a3111fc08f..5ca0866209a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -29,6 +29,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
@@ -100,6 +101,7 @@ public class ExpandableNotificationRowController implements NotifViewController
private final SmartReplyController mSmartReplyController;
private final ExpandableNotificationRowDragController mDragController;
private final NotificationDismissibilityProvider mDismissibilityProvider;
+ private final IStatusBarService mStatusBarService;
private final ExpandableNotificationRow.ExpandableNotificationRowLogger mLoggerCallback =
new ExpandableNotificationRow.ExpandableNotificationRowLogger() {
@Override
@@ -157,7 +159,8 @@ public class ExpandableNotificationRowController implements NotifViewController
PeopleNotificationIdentifier peopleNotificationIdentifier,
Optional<BubblesManager> bubblesManagerOptional,
ExpandableNotificationRowDragController dragController,
- NotificationDismissibilityProvider dismissibilityProvider) {
+ NotificationDismissibilityProvider dismissibilityProvider,
+ IStatusBarService statusBarService) {
mView = view;
mListContainer = listContainer;
mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory;
@@ -189,6 +192,7 @@ public class ExpandableNotificationRowController implements NotifViewController
mSmartReplyConstants = smartReplyConstants;
mSmartReplyController = smartReplyController;
mDismissibilityProvider = dismissibilityProvider;
+ mStatusBarService = statusBarService;
}
/**
@@ -220,7 +224,8 @@ public class ExpandableNotificationRowController implements NotifViewController
mMetricsLogger,
mSmartReplyConstants,
mSmartReplyController,
- mFeatureFlags
+ mFeatureFlags,
+ mStatusBarService
);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 5834dcbf8645..78392f78428f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -21,10 +21,13 @@ import android.annotation.Nullable;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.os.RemoteException;
import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.IndentingPrintWriter;
@@ -39,6 +42,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.RemoteInputController;
@@ -129,6 +133,7 @@ public class NotificationContentView extends FrameLayout implements Notification
private Runnable mExpandedVisibleListener;
private PeopleNotificationIdentifier mPeopleIdentifier;
private RemoteInputViewSubcomponent.Factory mRemoteInputSubcomponentFactory;
+ private IStatusBarService mStatusBarService;
/**
* List of listeners for when content views become inactive (i.e. not the showing view).
@@ -196,11 +201,13 @@ public class NotificationContentView extends FrameLayout implements Notification
PeopleNotificationIdentifier peopleNotificationIdentifier,
RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
SmartReplyConstants smartReplyConstants,
- SmartReplyController smartReplyController) {
+ SmartReplyController smartReplyController,
+ IStatusBarService statusBarService) {
mPeopleIdentifier = peopleNotificationIdentifier;
mRemoteInputSubcomponentFactory = rivSubcomponentFactory;
mSmartReplyConstants = smartReplyConstants;
mSmartReplyController = smartReplyController;
+ mStatusBarService = statusBarService;
}
public void reinflate() {
@@ -2193,4 +2200,36 @@ public class NotificationContentView extends FrameLayout implements Notification
protected void setHeadsUpWrapper(NotificationViewWrapper headsUpWrapper) {
mHeadsUpWrapper = headsUpWrapper;
}
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ try {
+ super.dispatchDraw(canvas);
+ } catch (Exception e) {
+ // Catch draw exceptions that may be caused by RemoteViews
+ Log.e(TAG, "Drawing view failed: " + e);
+ cancelNotification(e);
+ }
+ }
+
+ private void cancelNotification(Exception exception) {
+ try {
+ setVisibility(GONE);
+ final StatusBarNotification sbn = mNotificationEntry.getSbn();
+ if (mStatusBarService != null) {
+ // report notification inflation errors back up
+ // to notification delegates
+ mStatusBarService.onNotificationError(
+ sbn.getPackageName(),
+ sbn.getTag(),
+ sbn.getId(),
+ sbn.getUid(),
+ sbn.getInitialPid(),
+ exception.getMessage(),
+ sbn.getUser().getIdentifier());
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "cancelNotification failed: " + ex);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 0bded7327ea6..46603df955d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -809,6 +809,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
public void setOccludeAnimationPlaying(boolean occludeAnimationPlaying) {
mOccludeAnimationPlaying = occludeAnimationPlaying;
+
+ for (ScrimState state : ScrimState.values()) {
+ state.setOccludeAnimationPlaying(occludeAnimationPlaying);
+ }
+
applyAndDispatchState();
}
@@ -853,7 +858,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
if (mState == ScrimState.UNLOCKED || mState == ScrimState.DREAMING) {
final boolean occluding =
mOccludeAnimationPlaying || mState.mLaunchingAffordanceWithPreview;
-
// Darken scrim as it's pulled down while unlocked. If we're unlocked but playing the
// screen off/occlusion animations, ignore expansion changes while those animations
// play.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 0e9d3ce33d5b..7b2028310a84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -243,7 +243,12 @@ public enum ScrimState {
: CentralSurfaces.FADE_KEYGUARD_DURATION;
boolean fromAod = previousState == AOD || previousState == PULSING;
- mAnimateChange = !mLaunchingAffordanceWithPreview && !fromAod;
+ // If launch/occlude animations were playing, they already animated the scrim
+ // alpha to 0f as part of the animation. If we animate it now, we'll set it back
+ // to 1f and animate it back to 0f, causing an unwanted scrim flash.
+ mAnimateChange = !mLaunchingAffordanceWithPreview
+ && !mOccludeAnimationPlaying
+ && !fromAod;
mFrontTint = Color.TRANSPARENT;
mBehindTint = Color.BLACK;
@@ -308,6 +313,7 @@ public enum ScrimState {
boolean mWallpaperSupportsAmbientMode;
boolean mHasBackdrop;
boolean mLaunchingAffordanceWithPreview;
+ boolean mOccludeAnimationPlaying;
boolean mWakeLockScreenSensorActive;
boolean mKeyguardFadingAway;
long mKeyguardFadingAwayDuration;
@@ -411,6 +417,10 @@ public enum ScrimState {
mLaunchingAffordanceWithPreview = launchingAffordanceWithPreview;
}
+ public void setOccludeAnimationPlaying(boolean occludeAnimationPlaying) {
+ mOccludeAnimationPlaying = occludeAnimationPlaying;
+ }
+
public boolean isLowPowerState() {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index a0a0372426ec..209ea41fed61 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -59,6 +59,7 @@ import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.MessageRouter;
@@ -412,6 +413,7 @@ public class GarbageMonitor implements Dumpable {
private final GarbageMonitor gm;
private ProcessMemInfo pmi;
private boolean dumpInProgress;
+ private final PanelInteractor mPanelInteractor;
@Inject
public MemoryTile(
@@ -423,11 +425,13 @@ public class GarbageMonitor implements Dumpable {
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
- GarbageMonitor monitor
+ GarbageMonitor monitor,
+ PanelInteractor panelInteractor
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
gm = monitor;
+ mPanelInteractor = panelInteractor;
}
@Override
@@ -457,7 +461,7 @@ public class GarbageMonitor implements Dumpable {
mHandler.post(() -> {
dumpInProgress = false;
refreshState();
- getHost().collapsePanels();
+ mPanelInteractor.collapsePanels();
mActivityStarter.postStartActivityDismissingKeyguard(shareIntent, 0);
});
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 64e9a3e58bd6..7e052bfa15d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.when;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
+import android.os.Binder;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -41,6 +42,7 @@ import android.testing.TestableLooper.RunWithLooper;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -91,6 +93,8 @@ public class TileServicesTest extends SysuiTestCase {
private TileLifecycleManager mTileLifecycleManager;
@Mock
private QSHost mQSHost;
+ @Mock
+ private PanelInteractor mPanelInteractor;
@Before
public void setUp() throws Exception {
@@ -107,7 +111,8 @@ public class TileServicesTest extends SysuiTestCase {
Provider<Handler> provider = () -> new Handler(mTestableLooper.getLooper());
mTileService = new TestTileServices(mQSHost, provider, mBroadcastDispatcher,
- mUserTracker, mKeyguardStateController, mCommandQueue, mStatusBarIconController);
+ mUserTracker, mKeyguardStateController, mCommandQueue, mStatusBarIconController,
+ mPanelInteractor);
}
@After
@@ -222,13 +227,37 @@ public class TileServicesTest extends SysuiTestCase {
verify(tile, never()).startActivityAndCollapse(pi);
}
+ @Test
+ public void testOnStartActivityCollapsesPanel() {
+ CustomTile tile = mock(CustomTile.class);
+ ComponentName componentName = mock(ComponentName.class);
+ when(tile.getComponent()).thenReturn(componentName);
+ when(componentName.getPackageName()).thenReturn(this.getContext().getPackageName());
+ TileServiceManager manager = mTileService.getTileWrapper(tile);
+
+ mTileService.onStartActivity(manager.getToken());
+ verify(mPanelInteractor).forceCollapsePanels();
+ }
+
+ @Test
+ public void testOnShowDialogCollapsesPanel() {
+ CustomTile tile = mock(CustomTile.class);
+ ComponentName componentName = mock(ComponentName.class);
+ when(tile.getComponent()).thenReturn(componentName);
+ when(componentName.getPackageName()).thenReturn(this.getContext().getPackageName());
+ TileServiceManager manager = mTileService.getTileWrapper(tile);
+
+ mTileService.onShowDialog(manager.getToken());
+ verify(mPanelInteractor).forceCollapsePanels();
+ }
+
private class TestTileServices extends TileServices {
TestTileServices(QSHost host, Provider<Handler> handlerProvider,
BroadcastDispatcher broadcastDispatcher, UserTracker userTracker,
KeyguardStateController keyguardStateController, CommandQueue commandQueue,
- StatusBarIconController statusBarIconController) {
+ StatusBarIconController statusBarIconController, PanelInteractor panelInteractor) {
super(host, handlerProvider, broadcastDispatcher, userTracker, keyguardStateController,
- commandQueue, statusBarIconController);
+ commandQueue, statusBarIconController, panelInteractor);
}
@Override
@@ -237,6 +266,8 @@ public class TileServicesTest extends SysuiTestCase {
TileServiceManager manager = mock(TileServiceManager.class);
mManagers.add(manager);
when(manager.isLifecycleStarted()).thenReturn(true);
+ Binder b = new Binder();
+ when(manager.getToken()).thenReturn(b);
return manager;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
new file mode 100644
index 000000000000..45783abe9ee4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
@@ -0,0 +1,76 @@
+/*
+ * 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
+ */
+package com.android.systemui.qs.pipeline.domain.interactor
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import java.util.Optional
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class PanelInteractorImplTest : SysuiTestCase() {
+
+ @Mock private lateinit var centralSurfaces: CentralSurfaces
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun openPanels_callsCentralSurfaces() {
+ val underTest = PanelInteractorImpl(Optional.of(centralSurfaces))
+
+ underTest.openPanels()
+
+ verify(centralSurfaces).postAnimateOpenPanels()
+ }
+
+ @Test
+ fun collapsePanels_callsCentralSurfaces() {
+ val underTest = PanelInteractorImpl(Optional.of(centralSurfaces))
+
+ underTest.collapsePanels()
+
+ verify(centralSurfaces).postAnimateCollapsePanels()
+ }
+
+ @Test
+ fun forceCollapsePanels_callsCentralSurfaces() {
+ val underTest = PanelInteractorImpl(Optional.of(centralSurfaces))
+
+ underTest.forceCollapsePanels()
+
+ verify(centralSurfaces).postAnimateForceCollapsePanels()
+ }
+
+ @Test
+ fun whenOptionalEmpty_doesnThrow() {
+ val underTest = PanelInteractorImpl(Optional.empty())
+
+ underTest.openPanels()
+ underTest.collapsePanels()
+ underTest.forceCollapsePanels()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
index 33921c7c84b1..3642e874e7ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
@@ -31,9 +31,12 @@ import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.policy.LocationController
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -41,6 +44,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -65,6 +69,8 @@ class LocationTileTest : SysuiTestCase() {
private lateinit var locationController: LocationController
@Mock
private lateinit var keyguardStateController: KeyguardStateController
+ @Mock
+ private lateinit var panelInteractor: PanelInteractor
private val uiEventLogger = UiEventLoggerFake()
private lateinit var testableLooper: TestableLooper
@@ -86,7 +92,9 @@ class LocationTileTest : SysuiTestCase() {
activityStarter,
qsLogger,
locationController,
- keyguardStateController)
+ keyguardStateController,
+ panelInteractor,
+ )
}
@After
@@ -116,4 +124,18 @@ class LocationTileTest : SysuiTestCase() {
assertThat(state.icon)
.isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_location_icon_on))
}
+
+ @Test
+ fun testClickWhenLockedWillCallOpenPanels() {
+ `when`(keyguardStateController.isMethodSecure).thenReturn(true)
+ `when`(keyguardStateController.isShowing).thenReturn(true)
+
+ tile.handleClick(null)
+
+ val captor = argumentCaptor<Runnable>()
+ verify(activityStarter).postQSRunnableDismissingKeyguard(capture(captor))
+ captor.value.run()
+
+ verify(panelInteractor).openPanels()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 5aef75832fac..d9ed1a299f51 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -45,6 +45,7 @@ import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
@@ -83,6 +84,8 @@ public class ScreenRecordTileTest extends SysuiTestCase {
private KeyguardStateController mKeyguardStateController;
@Mock
private DialogLaunchAnimator mDialogLaunchAnimator;
+ @Mock
+ private PanelInteractor mPanelInteractor;
private TestableLooper mTestableLooper;
private ScreenRecordTile mTile;
@@ -108,7 +111,8 @@ public class ScreenRecordTileTest extends SysuiTestCase {
mController,
mKeyguardDismissUtil,
mKeyguardStateController,
- mDialogLaunchAnimator
+ mDialogLaunchAnimator,
+ mPanelInteractor
);
mTile.initialize();
@@ -146,7 +150,7 @@ public class ScreenRecordTileTest extends SysuiTestCase {
assertNotNull(onStartRecordingClicked.getValue());
onStartRecordingClicked.getValue().run();
verify(mDialogLaunchAnimator).disableAllCurrentDialogsExitAnimations();
- verify(mHost).collapsePanels();
+ verify(mPanelInteractor).collapsePanels();
}
// Test that the tile is active and labeled correctly when the controller is starting
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
index 15b84238dd19..d8ffe39e427d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
@@ -275,9 +275,7 @@ public class QuickSettingsControllerTest extends SysuiTestCase {
@Test
public void testPanelStaysOpenWhenClosingQs() {
- mShadeExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 1,
- /* expanded= */ true, /* tracking= */ false, /* dragDownPxAmount= */ 0);
- mQsController.setShadeExpandedHeight(1);
+ mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 1);
float shadeExpandedHeight = mQsController.getShadeExpandedHeight();
mQsController.animateCloseQs(false);
@@ -289,7 +287,7 @@ public class QuickSettingsControllerTest extends SysuiTestCase {
public void interceptTouchEvent_withinQs_shadeExpanded_startsQsTracking() {
mQsController.setQs(mQs);
- mQsController.setShadeExpandedHeight(1f);
+ mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 1);
mQsController.onIntercept(
createMotionEvent(0, 0, ACTION_DOWN));
mQsController.onIntercept(
@@ -303,7 +301,7 @@ public class QuickSettingsControllerTest extends SysuiTestCase {
enableSplitShade(true);
mQsController.setQs(mQs);
- mQsController.setShadeExpandedHeight(1f);
+ mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 1);
mQsController.onIntercept(
createMotionEvent(0, 0, ACTION_DOWN));
mQsController.onIntercept(
@@ -342,13 +340,8 @@ public class QuickSettingsControllerTest extends SysuiTestCase {
public void handleTouch_downActionInQsArea() {
mQsController.setQs(mQs);
mQsController.setBarState(SHADE);
- mQsController.onPanelExpansionChanged(
- new ShadeExpansionChangeEvent(
- 0.5f,
- true,
- true,
- 0
- ));
+ mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 0.5f);
+
MotionEvent event =
createMotionEvent(QS_FRAME_WIDTH / 2, QS_FRAME_BOTTOM / 2, ACTION_DOWN);
mQsController.handleTouch(event, false, false);
@@ -385,7 +378,7 @@ public class QuickSettingsControllerTest extends SysuiTestCase {
@Test
public void handleTouch_isConflictingExpansionGestureSet() {
assertThat(mQsController.isConflictingExpansionGesture()).isFalse();
- mShadeExpansionStateManager.onPanelExpansionChanged(1f, true, false, 0f);
+ mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 1);
mQsController.handleTouch(MotionEvent.obtain(0L /* downTime */,
0L /* eventTime */, ACTION_DOWN, 0f /* x */, 0f /* y */,
0 /* metaState */), false, false);
@@ -394,7 +387,7 @@ public class QuickSettingsControllerTest extends SysuiTestCase {
@Test
public void handleTouch_isConflictingExpansionGestureSet_cancel() {
- mShadeExpansionStateManager.onPanelExpansionChanged(1f, true, false, 0f);
+ mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 1);
mQsController.handleTouch(createMotionEvent(0, 0, ACTION_DOWN), false, false);
assertThat(mQsController.isConflictingExpansionGesture()).isTrue();
mQsController.handleTouch(createMotionEvent(0, 0, ACTION_UP), true, true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index 1fdb3647fcb2..374aae1f2948 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -27,13 +27,16 @@ import com.android.systemui.plugins.ClockMetadata
import com.android.systemui.plugins.ClockProviderPlugin
import com.android.systemui.plugins.ClockSettings
import com.android.systemui.plugins.PluginListener
+import com.android.systemui.plugins.PluginLifecycleManager
import com.android.systemui.plugins.PluginManager
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
import junit.framework.Assert.assertEquals
import junit.framework.Assert.fail
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.TestScope
import org.junit.Before
import org.junit.Rule
@@ -49,6 +52,7 @@ import org.mockito.junit.MockitoJUnit
class ClockRegistryTest : SysuiTestCase() {
@JvmField @Rule val mockito = MockitoJUnit.rule()
+ private lateinit var scheduler: TestCoroutineScheduler
private lateinit var dispatcher: CoroutineDispatcher
private lateinit var scope: TestScope
@@ -58,37 +62,38 @@ class ClockRegistryTest : SysuiTestCase() {
@Mock private lateinit var mockDefaultClock: ClockController
@Mock private lateinit var mockThumbnail: Drawable
@Mock private lateinit var mockContentResolver: ContentResolver
+ @Mock private lateinit var mockPluginLifecycle: PluginLifecycleManager<ClockProviderPlugin>
private lateinit var fakeDefaultProvider: FakeClockPlugin
private lateinit var pluginListener: PluginListener<ClockProviderPlugin>
private lateinit var registry: ClockRegistry
companion object {
- private fun failFactory(): ClockController {
- fail("Unexpected call to createClock")
+ private fun failFactory(clockId: ClockId): ClockController {
+ fail("Unexpected call to createClock: $clockId")
return null!!
}
- private fun failThumbnail(): Drawable? {
- fail("Unexpected call to getThumbnail")
+ private fun failThumbnail(clockId: ClockId): Drawable? {
+ fail("Unexpected call to getThumbnail: $clockId")
return null
}
}
private class FakeClockPlugin : ClockProviderPlugin {
private val metadata = mutableListOf<ClockMetadata>()
- private val createCallbacks = mutableMapOf<ClockId, () -> ClockController>()
- private val thumbnailCallbacks = mutableMapOf<ClockId, () -> Drawable?>()
+ private val createCallbacks = mutableMapOf<ClockId, (ClockId) -> ClockController>()
+ private val thumbnailCallbacks = mutableMapOf<ClockId, (ClockId) -> Drawable?>()
override fun getClocks() = metadata
override fun createClock(settings: ClockSettings): ClockController =
- createCallbacks[settings.clockId!!]!!()
- override fun getClockThumbnail(id: ClockId): Drawable? = thumbnailCallbacks[id]!!()
+ createCallbacks[settings.clockId!!]!!(settings.clockId!!)
+ override fun getClockThumbnail(id: ClockId): Drawable? = thumbnailCallbacks[id]!!(id)
fun addClock(
id: ClockId,
name: String,
- create: () -> ClockController = ::failFactory,
- getThumbnail: () -> Drawable? = ::failThumbnail
+ create: (ClockId) -> ClockController = ::failFactory,
+ getThumbnail: (ClockId) -> Drawable? = ::failThumbnail
): FakeClockPlugin {
metadata.add(ClockMetadata(id, name))
createCallbacks[id] = create
@@ -99,7 +104,8 @@ class ClockRegistryTest : SysuiTestCase() {
@Before
fun setUp() {
- dispatcher = StandardTestDispatcher()
+ scheduler = TestCoroutineScheduler()
+ dispatcher = StandardTestDispatcher(scheduler)
scope = TestScope(dispatcher)
fakeDefaultProvider = FakeClockPlugin()
@@ -116,6 +122,8 @@ class ClockRegistryTest : SysuiTestCase() {
isEnabled = true,
handleAllUsers = true,
defaultClockProvider = fakeDefaultProvider,
+ keepAllLoaded = true,
+ subTag = "Test",
) {
override fun querySettings() { }
override fun applySettings(value: ClockSettings?) {
@@ -142,8 +150,8 @@ class ClockRegistryTest : SysuiTestCase() {
.addClock("clock_3", "clock 3")
.addClock("clock_4", "clock 4")
- pluginListener.onPluginConnected(plugin1, mockContext)
- pluginListener.onPluginConnected(plugin2, mockContext)
+ pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle)
+ pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle)
val list = registry.getClocks()
assertEquals(
list,
@@ -165,16 +173,18 @@ class ClockRegistryTest : SysuiTestCase() {
@Test
fun clockIdConflict_ErrorWithoutCrash() {
+ val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
val plugin1 = FakeClockPlugin()
.addClock("clock_1", "clock 1", { mockClock }, { mockThumbnail })
.addClock("clock_2", "clock 2", { mockClock }, { mockThumbnail })
+ val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
val plugin2 = FakeClockPlugin()
.addClock("clock_1", "clock 1")
.addClock("clock_2", "clock 2")
- pluginListener.onPluginConnected(plugin1, mockContext)
- pluginListener.onPluginConnected(plugin2, mockContext)
+ pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle1)
+ pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle2)
val list = registry.getClocks()
assertEquals(
list,
@@ -202,8 +212,8 @@ class ClockRegistryTest : SysuiTestCase() {
.addClock("clock_4", "clock 4")
registry.applySettings(ClockSettings("clock_3", null))
- pluginListener.onPluginConnected(plugin1, mockContext)
- pluginListener.onPluginConnected(plugin2, mockContext)
+ pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle)
+ pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle)
val clock = registry.createCurrentClock()
assertEquals(mockClock, clock)
@@ -220,9 +230,9 @@ class ClockRegistryTest : SysuiTestCase() {
.addClock("clock_4", "clock 4")
registry.applySettings(ClockSettings("clock_3", null))
- pluginListener.onPluginConnected(plugin1, mockContext)
- pluginListener.onPluginConnected(plugin2, mockContext)
- pluginListener.onPluginDisconnected(plugin2)
+ pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle)
+ pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle)
+ pluginListener.onPluginUnloaded(plugin2, mockPluginLifecycle)
val clock = registry.createCurrentClock()
assertEquals(clock, mockDefaultClock)
@@ -230,15 +240,16 @@ class ClockRegistryTest : SysuiTestCase() {
@Test
fun pluginRemoved_clockAndListChanged() {
+ val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
val plugin1 = FakeClockPlugin()
.addClock("clock_1", "clock 1")
.addClock("clock_2", "clock 2")
+ val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
val plugin2 = FakeClockPlugin()
.addClock("clock_3", "clock 3", { mockClock })
.addClock("clock_4", "clock 4")
-
var changeCallCount = 0
var listChangeCallCount = 0
registry.registerClockChangeListener(object : ClockRegistry.ClockChangeListener {
@@ -247,23 +258,38 @@ class ClockRegistryTest : SysuiTestCase() {
})
registry.applySettings(ClockSettings("clock_3", null))
- assertEquals(0, changeCallCount)
+ scheduler.runCurrent()
+ assertEquals(1, changeCallCount)
assertEquals(0, listChangeCallCount)
- pluginListener.onPluginConnected(plugin1, mockContext)
- assertEquals(0, changeCallCount)
+ pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle1)
+ scheduler.runCurrent()
+ assertEquals(1, changeCallCount)
assertEquals(1, listChangeCallCount)
- pluginListener.onPluginConnected(plugin2, mockContext)
- assertEquals(1, changeCallCount)
+ pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle2)
+ scheduler.runCurrent()
+ assertEquals(2, changeCallCount)
assertEquals(2, listChangeCallCount)
- pluginListener.onPluginDisconnected(plugin1)
- assertEquals(1, changeCallCount)
+ pluginListener.onPluginUnloaded(plugin1, mockPluginLifecycle1)
+ scheduler.runCurrent()
+ assertEquals(2, changeCallCount)
+ assertEquals(2, listChangeCallCount)
+
+ pluginListener.onPluginUnloaded(plugin2, mockPluginLifecycle2)
+ scheduler.runCurrent()
+ assertEquals(3, changeCallCount)
+ assertEquals(2, listChangeCallCount)
+
+ pluginListener.onPluginDetached(mockPluginLifecycle1)
+ scheduler.runCurrent()
+ assertEquals(3, changeCallCount)
assertEquals(3, listChangeCallCount)
- pluginListener.onPluginDisconnected(plugin2)
- assertEquals(2, changeCallCount)
+ pluginListener.onPluginDetached(mockPluginLifecycle2)
+ scheduler.runCurrent()
+ assertEquals(3, changeCallCount)
assertEquals(4, listChangeCallCount)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java
index 05280fa826ed..c39b29fb4435 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java
@@ -79,11 +79,11 @@ public class PluginActionManagerTest extends SysuiTestCase {
private PluginInstance<TestPlugin> mPluginInstance;
private PluginInstance.Factory mPluginInstanceFactory = new PluginInstance.Factory(
this.getClass().getClassLoader(),
- new PluginInstance.InstanceFactory<>(), new PluginInstance.VersionChecker(),
+ new PluginInstance.InstanceFactory<>(), new PluginInstance.VersionCheckerImpl(),
Collections.emptyList(), false) {
@Override
public <T extends Plugin> PluginInstance<T> create(Context context, ApplicationInfo appInfo,
- ComponentName componentName, Class<T> pluginClass) {
+ ComponentName componentName, Class<T> pluginClass, PluginListener<T> listener) {
return (PluginInstance<T>) mPluginInstance;
}
};
@@ -128,7 +128,7 @@ public class PluginActionManagerTest extends SysuiTestCase {
createPlugin();
// Verify startup lifecycle
- verify(mPluginInstance).onCreate(mContext, mMockListener);
+ verify(mPluginInstance).onCreate();
}
@Test
@@ -140,7 +140,7 @@ public class PluginActionManagerTest extends SysuiTestCase {
mFakeExecutor.runAllReady();
// Verify shutdown lifecycle
- verify(mPluginInstance).onDestroy(mMockListener);
+ verify(mPluginInstance).onDestroy();
}
@Test
@@ -152,9 +152,9 @@ public class PluginActionManagerTest extends SysuiTestCase {
mFakeExecutor.runAllReady();
// Verify the old one was destroyed.
- verify(mPluginInstance).onDestroy(mMockListener);
+ verify(mPluginInstance).onDestroy();
verify(mPluginInstance, Mockito.times(2))
- .onCreate(mContext, mMockListener);
+ .onCreate();
}
@Test
@@ -188,7 +188,7 @@ public class PluginActionManagerTest extends SysuiTestCase {
mFakeExecutor.runAllReady();
// Verify startup lifecycle
- verify(mPluginInstance).onCreate(mContext, mMockListener);
+ verify(mPluginInstance).onCreate();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
index bb9a1e971fd0..d5e904c636d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
@@ -16,11 +16,9 @@
package com.android.systemui.shared.plugins;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static junit.framework.Assert.assertNull;
import android.content.ComponentName;
import android.content.Context;
@@ -31,6 +29,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginLifecycleManager;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.annotations.ProvidesInterface;
import com.android.systemui.plugins.annotations.Requires;
@@ -38,46 +37,64 @@ import com.android.systemui.plugins.annotations.Requires;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import java.lang.ref.WeakReference;
import java.util.Collections;
+import java.util.concurrent.atomic.AtomicInteger;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class PluginInstanceTest extends SysuiTestCase {
private static final String PRIVILEGED_PACKAGE = "com.android.systemui.plugins";
+ private static final ComponentName TEST_PLUGIN_COMPONENT_NAME =
+ new ComponentName(PRIVILEGED_PACKAGE, TestPluginImpl.class.getName());
- @Mock
- private TestPluginImpl mMockPlugin;
- @Mock
- private PluginListener<TestPlugin> mMockListener;
- @Mock
+ private FakeListener mPluginListener;
private VersionInfo mVersionInfo;
- ComponentName mTestPluginComponentName =
- new ComponentName(PRIVILEGED_PACKAGE, TestPluginImpl.class.getName());
+ private VersionInfo.InvalidVersionException mVersionException;
+ private PluginInstance.VersionChecker mVersionChecker;
+
+ private RefCounter mCounter;
private PluginInstance<TestPlugin> mPluginInstance;
private PluginInstance.Factory mPluginInstanceFactory;
-
private ApplicationInfo mAppInfo;
- private Context mPluginContext;
- @Mock
- private PluginInstance.VersionChecker mVersionChecker;
+
+ // Because we're testing memory in this file, we must be careful not to assert the target
+ // objects, or capture them via mockito if we expect the garbage collector to later free them.
+ // Both JUnit and Mockito will save references and prevent these objects from being cleaned up.
+ private WeakReference<TestPluginImpl> mPlugin;
+ private WeakReference<Context> mPluginContext;
@Before
public void setup() throws Exception {
- MockitoAnnotations.initMocks(this);
+ mCounter = new RefCounter();
mAppInfo = mContext.getApplicationInfo();
- mAppInfo.packageName = mTestPluginComponentName.getPackageName();
- when(mVersionChecker.checkVersion(any(), any(), any())).thenReturn(mVersionInfo);
+ mAppInfo.packageName = TEST_PLUGIN_COMPONENT_NAME.getPackageName();
+ mPluginListener = new FakeListener();
+ mVersionInfo = new VersionInfo();
+ mVersionChecker = new PluginInstance.VersionChecker() {
+ @Override
+ public <T extends Plugin> VersionInfo checkVersion(
+ Class<T> instanceClass,
+ Class<T> pluginClass,
+ Plugin plugin
+ ) {
+ if (mVersionException != null) {
+ throw mVersionException;
+ }
+ return mVersionInfo;
+ }
+ };
mPluginInstanceFactory = new PluginInstance.Factory(
this.getClass().getClassLoader(),
new PluginInstance.InstanceFactory<TestPlugin>() {
@Override
TestPlugin create(Class cls) {
- return mMockPlugin;
+ TestPluginImpl plugin = new TestPluginImpl(mCounter);
+ mPlugin = new WeakReference<>(plugin);
+ return plugin;
}
},
mVersionChecker,
@@ -85,8 +102,9 @@ public class PluginInstanceTest extends SysuiTestCase {
false);
mPluginInstance = mPluginInstanceFactory.create(
- mContext, mAppInfo, mTestPluginComponentName, TestPlugin.class);
- mPluginContext = mPluginInstance.getPluginContext();
+ mContext, mAppInfo, TEST_PLUGIN_COMPONENT_NAME,
+ TestPlugin.class, mPluginListener);
+ mPluginContext = new WeakReference<>(mPluginInstance.getPluginContext());
}
@Test
@@ -96,29 +114,51 @@ public class PluginInstanceTest extends SysuiTestCase {
@Test(expected = VersionInfo.InvalidVersionException.class)
public void testIncorrectVersion() throws Exception {
-
ComponentName wrongVersionTestPluginComponentName =
new ComponentName(PRIVILEGED_PACKAGE, TestPlugin.class.getName());
- when(mVersionChecker.checkVersion(any(), any(), any())).thenThrow(
- new VersionInfo.InvalidVersionException("test", true));
+ mVersionException = new VersionInfo.InvalidVersionException("test", true);
mPluginInstanceFactory.create(
- mContext, mAppInfo, wrongVersionTestPluginComponentName, TestPlugin.class);
+ mContext, mAppInfo, wrongVersionTestPluginComponentName,
+ TestPlugin.class, mPluginListener);
}
@Test
public void testOnCreate() {
- mPluginInstance.onCreate(mContext, mMockListener);
- verify(mMockPlugin).onCreate(mContext, mPluginContext);
- verify(mMockListener).onPluginConnected(mMockPlugin, mPluginContext);
+ mPluginInstance.onCreate();
+ assertEquals(1, mPluginListener.mAttachedCount);
+ assertEquals(1, mPluginListener.mLoadCount);
+ assertEquals(mPlugin.get(), mPluginInstance.getPlugin());
+ assertInstances(1, 1);
}
@Test
public void testOnDestroy() {
- mPluginInstance.onDestroy(mMockListener);
- verify(mMockListener).onPluginDisconnected(mMockPlugin);
- verify(mMockPlugin).onDestroy();
+ mPluginInstance.onDestroy();
+ assertEquals(1, mPluginListener.mDetachedCount);
+ assertEquals(1, mPluginListener.mUnloadCount);
+ assertNull(mPluginInstance.getPlugin());
+ assertInstances(0, -1); // Destroyed but never created
+ }
+
+ @Test
+ public void testOnRepeatedlyLoadUnload_PluginFreed() {
+ mPluginInstance.onCreate();
+ mPluginInstance.loadPlugin();
+ assertInstances(1, 1);
+
+ mPluginInstance.unloadPlugin();
+ assertNull(mPluginInstance.getPlugin());
+ assertInstances(0, 0);
+
+ mPluginInstance.loadPlugin();
+ assertInstances(1, 1);
+
+ mPluginInstance.unloadPlugin();
+ mPluginInstance.onDestroy();
+ assertNull(mPluginInstance.getPlugin());
+ assertInstances(0, 0);
}
// This target class doesn't matter, it just needs to have a Requires to hit the flow where
@@ -129,10 +169,103 @@ public class PluginInstanceTest extends SysuiTestCase {
String ACTION = "testAction";
}
+ public void assertInstances(Integer allocated, Integer created) {
+ // Run the garbage collector to finalize and deallocate outstanding
+ // instances. Since the GC doesn't always appear to want to run
+ // completely when we ask, we ask it 10 times in a short loop.
+ for (int i = 0; i < 10; i++) {
+ System.runFinalization();
+ System.gc();
+ }
+
+ mCounter.assertInstances(allocated, created);
+ }
+
+ public static class RefCounter {
+ public final AtomicInteger mAllocatedInstances = new AtomicInteger();
+ public final AtomicInteger mCreatedInstances = new AtomicInteger();
+
+ public void assertInstances(Integer allocated, Integer created) {
+ if (allocated != null) {
+ assertEquals(allocated.intValue(), mAllocatedInstances.get());
+ }
+ if (created != null) {
+ assertEquals(created.intValue(), mCreatedInstances.get());
+ }
+ }
+ }
+
@Requires(target = TestPlugin.class, version = TestPlugin.VERSION)
public static class TestPluginImpl implements TestPlugin {
+ public final RefCounter mCounter;
+ public TestPluginImpl(RefCounter counter) {
+ mCounter = counter;
+ mCounter.mAllocatedInstances.getAndIncrement();
+ }
+
+ @Override
+ public void finalize() {
+ mCounter.mAllocatedInstances.getAndDecrement();
+ }
+
@Override
public void onCreate(Context sysuiContext, Context pluginContext) {
+ mCounter.mCreatedInstances.getAndIncrement();
+ }
+
+ @Override
+ public void onDestroy() {
+ mCounter.mCreatedInstances.getAndDecrement();
+ }
+ }
+
+ public class FakeListener implements PluginListener<TestPlugin> {
+ public int mAttachedCount = 0;
+ public int mDetachedCount = 0;
+ public int mLoadCount = 0;
+ public int mUnloadCount = 0;
+
+ @Override
+ public void onPluginAttached(PluginLifecycleManager<TestPlugin> manager) {
+ mAttachedCount++;
+ assertEquals(PluginInstanceTest.this.mPluginInstance, manager);
+ }
+
+ @Override
+ public void onPluginDetached(PluginLifecycleManager<TestPlugin> manager) {
+ mDetachedCount++;
+ assertEquals(PluginInstanceTest.this.mPluginInstance, manager);
+ }
+
+ @Override
+ public void onPluginLoaded(
+ TestPlugin plugin,
+ Context pluginContext,
+ PluginLifecycleManager<TestPlugin> manager
+ ) {
+ mLoadCount++;
+ TestPlugin expectedPlugin = PluginInstanceTest.this.mPlugin.get();
+ if (expectedPlugin != null) {
+ assertEquals(expectedPlugin, plugin);
+ }
+ Context expectedContext = PluginInstanceTest.this.mPluginContext.get();
+ if (expectedContext != null) {
+ assertEquals(expectedContext, pluginContext);
+ }
+ assertEquals(PluginInstanceTest.this.mPluginInstance, manager);
+ }
+
+ @Override
+ public void onPluginUnloaded(
+ TestPlugin plugin,
+ PluginLifecycleManager<TestPlugin> manager
+ ) {
+ mUnloadCount++;
+ TestPlugin expectedPlugin = PluginInstanceTest.this.mPlugin.get();
+ if (expectedPlugin != null) {
+ assertEquals(expectedPlugin, plugin);
+ }
+ assertEquals(PluginInstanceTest.this.mPluginInstance, manager);
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index c92134b2212b..60bc3a45c0dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -21,6 +21,7 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
+import com.android.internal.statusbar.IStatusBarService
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FeatureFlags
@@ -93,6 +94,7 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
private val bubblesManager: BubblesManager = mock()
private val dragController: ExpandableNotificationRowDragController = mock()
private val dismissibilityProvider: NotificationDismissibilityProvider = mock()
+ private val statusBarService: IStatusBarService = mock()
private lateinit var controller: ExpandableNotificationRowController
@@ -130,7 +132,8 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
peopleNotificationIdentifier,
Optional.of(bubblesManager),
dragController,
- dismissibilityProvider
+ dismissibilityProvider,
+ statusBarService
)
whenever(view.childrenContainer).thenReturn(childrenContainer)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
index 7b2051da4d15..0b90ebec3ec6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
@@ -74,7 +74,7 @@ class NotificationContentViewTest : SysuiTestCase() {
doReturn(10).whenever(spyRow).intrinsicHeight
with(view) {
- initialize(mPeopleNotificationIdentifier, mock(), mock(), mock())
+ initialize(mPeopleNotificationIdentifier, mock(), mock(), mock(), mock())
setContainingNotification(spyRow)
setHeights(/* smallHeight= */ 10, /* headsUpMaxHeight= */ 20, /* maxHeight= */ 30)
contractedChild = createViewWithHeight(10)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index f8a8e50efb4c..813bae893569 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -49,6 +49,7 @@ import android.view.LayoutInflater;
import android.widget.RemoteViews;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.TestableDependency;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
@@ -582,7 +583,8 @@ public class NotificationTestHelper {
mock(MetricsLogger.class),
mock(SmartReplyConstants.class),
mock(SmartReplyController.class),
- mFeatureFlags);
+ mFeatureFlags,
+ mock(IStatusBarService.class));
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 7a1270f3521d..a9ed17531926 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -25,6 +25,7 @@ import static com.android.systemui.statusbar.phone.ScrimState.SHADE_LOCKED;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -1163,8 +1164,8 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void testScrimFocus() {
mScrimController.transitionTo(ScrimState.AOD);
- Assert.assertFalse("Should not be focusable on AOD", mScrimBehind.isFocusable());
- Assert.assertFalse("Should not be focusable on AOD", mScrimInFront.isFocusable());
+ assertFalse("Should not be focusable on AOD", mScrimBehind.isFocusable());
+ assertFalse("Should not be focusable on AOD", mScrimInFront.isFocusable());
mScrimController.transitionTo(ScrimState.KEYGUARD);
Assert.assertTrue("Should be focusable on keyguard", mScrimBehind.isFocusable());
@@ -1224,7 +1225,7 @@ public class ScrimControllerTest extends SysuiTestCase {
public void testAnimatesTransitionToAod() {
when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
ScrimState.AOD.prepare(ScrimState.KEYGUARD);
- Assert.assertFalse("No animation when ColorFade kicks in",
+ assertFalse("No animation when ColorFade kicks in",
ScrimState.AOD.getAnimateChange());
reset(mDozeParameters);
@@ -1236,9 +1237,9 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void testViewsDontHaveFocusHighlight() {
- Assert.assertFalse("Scrim shouldn't have focus highlight",
+ assertFalse("Scrim shouldn't have focus highlight",
mScrimInFront.getDefaultFocusHighlightEnabled());
- Assert.assertFalse("Scrim shouldn't have focus highlight",
+ assertFalse("Scrim shouldn't have focus highlight",
mScrimBehind.getDefaultFocusHighlightEnabled());
}
@@ -1738,7 +1739,7 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void aodStateSetsFrontScrimToNotBlend() {
mScrimController.transitionTo(ScrimState.AOD);
- Assert.assertFalse("Front scrim should not blend with main color",
+ assertFalse("Front scrim should not blend with main color",
mScrimInFront.shouldBlendWithMainColor());
}
@@ -1773,6 +1774,14 @@ public class ScrimControllerTest extends SysuiTestCase {
verify(mStatusBarKeyguardViewManager).onKeyguardFadedAway();
}
+ @Test
+ public void testDoNotAnimateChangeIfOccludeAnimationPlaying() {
+ mScrimController.setOccludeAnimationPlaying(true);
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+
+ assertFalse(ScrimState.UNLOCKED.mAnimateChange);
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
index 481d453fa0b1..c8f28bc17926 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -55,6 +55,9 @@ import org.mockito.MockitoAnnotations;
public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase {
private static final String[] DEFAULT_SETTINGS = new String[]{"0:1", "2:0:1", "1:2"};
+ private static final int[] DEFAULT_FOLDED_STATES = new int[]{0};
+ private static final int[] DEFAULT_HALF_FOLDED_STATES = new int[]{2};
+ private static final int[] DEFAULT_UNFOLDED_STATES = new int[]{1};
@Mock private DeviceStateManager mDeviceStateManager;
@Mock private DeviceStateRotationLockSettingControllerLogger mLogger;
@@ -73,6 +76,9 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
MockitoAnnotations.initMocks(/* testClass= */ this);
TestableResources resources = mContext.getOrCreateTestableResources();
resources.addOverride(R.array.config_perDeviceStateRotationLockDefaults, DEFAULT_SETTINGS);
+ resources.addOverride(R.array.config_foldedDeviceStates, DEFAULT_FOLDED_STATES);
+ resources.addOverride(R.array.config_halfFoldedDeviceStates, DEFAULT_HALF_FOLDED_STATES);
+ resources.addOverride(R.array.config_openDeviceStates, DEFAULT_UNFOLDED_STATES);
ArgumentCaptor<DeviceStateManager.DeviceStateCallback> deviceStateCallbackArgumentCaptor =
ArgumentCaptor.forClass(DeviceStateManager.DeviceStateCallback.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 8e3988b2c038..ee4e00baafe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -1245,6 +1245,24 @@ public class BubblesTest extends SysuiTestCase {
// Show the menu
stackView.showManageMenu(true);
assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */);
+ assertTrue(stackView.isManageMenuSettingsVisible());
+ }
+
+ @Test
+ public void testShowManageMenuChangesSysuiState_appBubble() {
+ mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0);
+ assertTrue(mBubbleController.hasBubbles());
+
+ // Expand the stack
+ BubbleStackView stackView = mBubbleController.getStackView();
+ mBubbleData.setExpanded(true);
+ assertStackExpanded();
+ assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+
+ // Show the menu
+ stackView.showManageMenu(true);
+ assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */);
+ assertFalse(stackView.isManageMenuSettingsVisible());
}
@Test
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 755019684da6..b4e75e193b65 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9351,7 +9351,9 @@ public class ActivityManagerService extends IActivityManager.Stub
String logcatSetting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
String maxBytesSetting = Settings.Global.MAX_ERROR_BYTES_PREFIX + dropboxTag;
- int lines = Settings.Global.getInt(mContext.getContentResolver(), logcatSetting, 0);
+ int lines = Build.IS_USER
+ ? 0
+ : Settings.Global.getInt(mContext.getContentResolver(), logcatSetting, 0);
int dropboxMaxSize = Settings.Global.getInt(
mContext.getContentResolver(), maxBytesSetting, DROPBOX_DEFAULT_MAX_SIZE);
int maxDataFileSize = dropboxMaxSize - sb.length()
diff --git a/services/core/java/com/android/server/biometrics/TEST_MAPPING b/services/core/java/com/android/server/biometrics/TEST_MAPPING
index 8b80674070a4..daca00b40768 100644
--- a/services/core/java/com/android/server/biometrics/TEST_MAPPING
+++ b/services/core/java/com/android/server/biometrics/TEST_MAPPING
@@ -6,5 +6,24 @@
{
"name": "CtsBiometricsHostTestCases"
}
- ]
-} \ No newline at end of file
+ ],
+ "ironwood-postsubmit": [
+ {
+ "name": "BiometricsE2eTests",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.IwTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.platform.test.scenario.biometrics"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index dc00ffc9f922..01ffc7e29ac0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -314,7 +314,8 @@ public class FingerprintService extends SystemService {
final FingerprintSensorPropertiesInternal sensorProps =
provider.second.getSensorProperties(options.getSensorId());
if (!isKeyguard && !Utils.isSettings(getContext(), opPackageName)
- && sensorProps != null && sensorProps.isAnyUdfpsType()) {
+ && sensorProps != null && (sensorProps.isAnyUdfpsType()
+ || sensorProps.isAnySidefpsType())) {
try {
return authenticateWithPrompt(operationId, sensorProps, callingUid,
callingUserId, receiver, opPackageName,
diff --git a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
index 77cd67304729..a081dff9e62d 100644
--- a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
@@ -92,6 +92,8 @@ public class GnssConfiguration {
// Represents an HAL interface version. Instances of this class are created in the JNI layer
// and returned through native methods.
static class HalInterfaceVersion {
+ // mMajor being this value denotes AIDL HAL. In this case, mMinor denotes the AIDL version.
+ static final int AIDL_INTERFACE = 3;
final int mMajor;
final int mMinor;
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index 6c4c829b051d..041f11d972fe 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -21,6 +21,7 @@ import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
import static com.android.server.location.gnss.GnssManagerService.D;
import static com.android.server.location.gnss.GnssManagerService.TAG;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.location.GnssMeasurementRequest;
@@ -31,6 +32,7 @@ import android.os.IBinder;
import android.stats.location.LocationStatsEnums;
import android.util.Log;
+import com.android.server.location.gnss.GnssConfiguration.HalInterfaceVersion;
import com.android.server.location.gnss.hal.GnssNative;
import com.android.server.location.injector.AppOpsHelper;
import com.android.server.location.injector.Injector;
@@ -115,16 +117,6 @@ public final class GnssMeasurementsProvider extends
if (request.getIntervalMillis() == GnssMeasurementRequest.PASSIVE_INTERVAL) {
return true;
}
- // The HAL doc does not specify if consecutive start() calls will be allowed.
- // Some vendors may ignore the 2nd start() call if stop() is not called.
- // Thus, here we always call stop() before calling start() to avoid being ignored.
- if (mGnssNative.stopMeasurementCollection()) {
- if (D) {
- Log.d(TAG, "stopping gnss measurements");
- }
- } else {
- Log.e(TAG, "error stopping gnss measurements");
- }
if (mGnssNative.startMeasurementCollection(request.isFullTracking(),
request.isCorrelationVectorOutputsEnabled(),
request.getIntervalMillis())) {
@@ -139,6 +131,28 @@ public final class GnssMeasurementsProvider extends
}
@Override
+ protected boolean reregisterWithService(GnssMeasurementRequest old,
+ GnssMeasurementRequest request,
+ @NonNull Collection<GnssListenerRegistration> registrations) {
+ if (request.getIntervalMillis() == GnssMeasurementRequest.PASSIVE_INTERVAL) {
+ unregisterWithService();
+ return true;
+ }
+ HalInterfaceVersion halInterfaceVersion =
+ mGnssNative.getConfiguration().getHalInterfaceVersion();
+ boolean aidlV3Plus = halInterfaceVersion.mMajor == HalInterfaceVersion.AIDL_INTERFACE
+ && halInterfaceVersion.mMinor >= 3;
+ if (!aidlV3Plus) {
+ // The HAL doc does not specify if consecutive start() calls will be allowed.
+ // Some vendors may ignore the 2nd start() call if stop() is not called.
+ // Thus, here we always call stop() before calling start() to avoid being ignored.
+ // AIDL v3+ is free from this issue.
+ unregisterWithService();
+ }
+ return registerWithService(request, registrations);
+ }
+
+ @Override
protected void unregisterWithService() {
if (mGnssNative.stopMeasurementCollection()) {
if (D) {
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index d160740712d3..5312ae6ca84c 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -69,7 +69,6 @@ final class ReconcilePackageUtils {
for (InstallRequest installRequest : installRequests) {
installRequest.onReconcileStarted();
- final String installPackageName = installRequest.getParsedPackage().getPackageName();
// add / replace existing with incoming packages
combinedPackages.put(installRequest.getScannedPackageSetting().getPackageName(),
@@ -84,12 +83,17 @@ final class ReconcilePackageUtils {
incomingSharedLibraries, info)) {
throw ReconcileFailure.ofInternalError(
"Shared Library " + info.getName()
- + " is being installed twice in this set!",
+ + " is being installed twice in this set!",
PackageManagerException.INTERNAL_ERROR_SHARED_LIB_INSTALLED_TWICE);
}
}
}
+ }
+ for (InstallRequest installRequest : installRequests) {
+ final String installPackageName = installRequest.getParsedPackage().getPackageName();
+ final List<SharedLibraryInfo> allowedSharedLibInfos =
+ sharedLibraries.getAllowedSharedLibInfos(installRequest);
final DeletePackageAction deletePackageAction;
// we only want to try to delete for non system apps
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 324a0adee693..e21c15665140 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4357,17 +4357,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
void addWindow(WindowState w) {
super.addWindow(w);
-
- boolean gotReplacementWindow = false;
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState candidate = mChildren.get(i);
- gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);
- }
-
- // if we got a replacement window, reset the timeout to give drawing more time
- if (gotReplacementWindow) {
- mWmService.scheduleWindowReplacementTimeouts(this);
- }
checkKeyguardFlagsChanged();
}
@@ -4382,12 +4371,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
updateLetterboxSurface(child);
}
- void onWindowReplacementTimeout() {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- (mChildren.get(i)).onWindowReplacementTimeout();
- }
- }
-
void setAppLayoutChanges(int changes, String reason) {
if (!mChildren.isEmpty()) {
final DisplayContent dc = getDisplayContent();
@@ -4398,15 +4381,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- void removeReplacedWindowIfNeeded(WindowState replacement) {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState win = mChildren.get(i);
- if (win.removeReplacedWindowIfNeeded(replacement)) {
- return;
- }
- }
- }
-
private boolean transferStartingWindow(@NonNull ActivityRecord fromActivity) {
final WindowState tStartingWindow = fromActivity.mStartingWindow;
if (tStartingWindow != null && fromActivity.mStartingSurface != null) {
@@ -5633,10 +5607,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// * activity is transitioning visibility state
// * or the activity was marked as hidden and is exiting before we had a chance to play the
// transition animation
- // * or this is an opening app and windows are being replaced (e.g. freeform window to
- // normal window).
- return isVisible() != visible || mRequestForceTransition || (!isVisible() && mIsExiting)
- || (visible && forAllWindows(WindowState::waitingForReplacement, true));
+ return isVisible() != visible || mRequestForceTransition || (!isVisible() && mIsExiting);
}
/**
@@ -7380,35 +7351,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- void setWillReplaceWindows(boolean animate) {
- ProtoLog.d(WM_DEBUG_ADD_REMOVE,
- "Marking app token %s with replacing windows.", this);
-
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState w = mChildren.get(i);
- w.setWillReplaceWindow(animate);
- }
- }
-
- void setWillReplaceChildWindows() {
- ProtoLog.d(WM_DEBUG_ADD_REMOVE, "Marking app token %s"
- + " with replacing child windows.", this);
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState w = mChildren.get(i);
- w.setWillReplaceChildWindows();
- }
- }
-
- void clearWillReplaceWindows() {
- ProtoLog.d(WM_DEBUG_ADD_REMOVE,
- "Resetting app token %s of replacing window marks.", this);
-
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState w = mChildren.get(i);
- w.clearWillReplaceWindow();
- }
- }
-
void requestUpdateWallpaperIfNeeded() {
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState w = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 0b28ba2bb146..bc9efc88ecae 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -377,15 +377,10 @@ class DragState {
mDragWindowHandle.ownerUid = MY_UID;
mDragWindowHandle.scaleFactor = 1.0f;
- // InputConfig.PREVENT_SPLITTING: To keep the default behavior of this window to be
- // focusable, which allows the system to consume keys when dragging is active. This can
- // also be used to modify the drag state on key press. For example, cancel drag on
- // escape key.
// InputConfig.TRUSTED_OVERLAY: To not block any touches while D&D ongoing and allowing
// touches to pass through to windows underneath. This allows user to interact with the
// UI to navigate while dragging.
- mDragWindowHandle.inputConfig =
- InputConfig.PREVENT_SPLITTING | InputConfig.TRUSTED_OVERLAY;
+ mDragWindowHandle.inputConfig = InputConfig.TRUSTED_OVERLAY;
// The drag window cannot receive new touches.
mDragWindowHandle.touchableRegion.setEmpty();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index b2a4df1f4692..fda2125be3cf 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -44,7 +44,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WALLPAPER;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
-import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.policy.PhoneWindowManager.SYSTEM_DIALOG_REASON_ASSIST;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -432,13 +431,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
};
- private static final Consumer<WindowState> sRemoveReplacedWindowsConsumer = w -> {
- final ActivityRecord activity = w.mActivityRecord;
- if (activity != null) {
- activity.removeReplacedWindowIfNeeded(w);
- }
- };
-
RootWindowContainer(WindowManagerService service) {
super(service);
mHandler = new MyHandler(service.mH.getLooper());
@@ -662,17 +654,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
forAllWindows(mCloseSystemDialogsConsumer, false /* traverseTopToBottom */);
}
- void removeReplacedWindows() {
- ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION removeReplacedWindows");
- mWmService.openSurfaceTransaction();
- try {
- forAllWindows(sRemoveReplacedWindowsConsumer, true /* traverseTopToBottom */);
- } finally {
- mWmService.closeSurfaceTransaction("removeReplacedWindows");
- ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION removeReplacedWindows");
- }
- }
-
boolean hasPendingLayoutChanges(WindowAnimator animator) {
boolean hasChanges = false;
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index ce9bff8521e6..78ee6f95fdba 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -232,11 +232,6 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
}
@Override
- public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) {
- mService.setWillReplaceWindows(appToken, childrenOnly);
- }
-
- @Override
public boolean cancelDraw(IWindow window) {
return mService.cancelDraw(this, window);
}
@@ -862,7 +857,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public void grantInputChannel(int displayId, SurfaceControl surface,
IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type,
- IBinder windowToken, IBinder focusGrantToken, String inputHandleName,
+ int inputFeatures, IBinder windowToken, IBinder focusGrantToken, String inputHandleName,
InputChannel outInputChannel) {
if (hostInputToken == null && !mCanAddInternalSystemWindow) {
// Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to
@@ -874,7 +869,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
try {
mService.grantInputChannel(this, mUid, mPid, displayId, surface, window, hostInputToken,
flags, mCanAddInternalSystemWindow ? privateFlags : 0,
- type, windowToken, focusGrantToken, inputHandleName,
+ type, inputFeatures, windowToken, focusGrantToken, inputHandleName,
outInputChannel);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -883,11 +878,11 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
- int flags, int privateFlags, Region region) {
+ int flags, int privateFlags, int inputFeatures, Region region) {
final long identity = Binder.clearCallingIdentity();
try {
mService.updateInputChannel(channelToken, displayId, surface, flags,
- mCanAddInternalSystemWindow ? privateFlags : 0, region);
+ mCanAddInternalSystemWindow ? privateFlags : 0, inputFeatures, region);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 67ca8443102b..6882e4c1d557 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -866,23 +866,8 @@ class Task extends TaskFragment {
return false;
}
- final int toRootTaskWindowingMode = toRootTask.getWindowingMode();
final ActivityRecord topActivity = getTopNonFinishingActivity();
- final boolean mightReplaceWindow = topActivity != null
- && replaceWindowsOnTaskMove(getWindowingMode(), toRootTaskWindowingMode);
- if (mightReplaceWindow) {
- // We are about to relaunch the activity because its configuration changed due to
- // being maximized, i.e. size change. The activity will first remove the old window
- // and then add a new one. This call will tell window manager about this, so it can
- // preserve the old window until the new one is drawn. This prevents having a gap
- // between the removal and addition, in which no window is visible. We also want the
- // entrance of the new window to be properly animated.
- // Note here we always set the replacing window first, as the flags might be needed
- // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
- windowManager.setWillReplaceWindow(topActivity.token, animate);
- }
-
mAtmService.deferWindowLayout();
boolean kept = true;
try {
@@ -926,17 +911,10 @@ class Task extends TaskFragment {
mAtmService.continueWindowLayout();
}
- if (mightReplaceWindow) {
- // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
- // window), we need to clear the replace window settings. Otherwise, we schedule a
- // timeout to remove the old window if the replacing window is not coming in time.
- windowManager.scheduleClearWillReplaceWindows(topActivity.token, !kept);
- }
-
if (!deferResume) {
// The task might have already been running and its visibility needs to be synchronized
// with the visibility of the root task / windows.
- root.ensureActivitiesVisible(null, 0, !mightReplaceWindow);
+ root.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
root.resumeFocusedTasksTopActivities();
}
@@ -947,17 +925,6 @@ class Task extends TaskFragment {
return (preferredRootTask == toRootTask);
}
- /**
- * @return {@code true} if the windows of tasks being moved to the target root task from the
- * source root task should be replaced, meaning that window manager will keep the old window
- * around until the new is ready.
- */
- private static boolean replaceWindowsOnTaskMove(
- int sourceWindowingMode, int targetWindowingMode) {
- return sourceWindowingMode == WINDOWING_MODE_FREEFORM
- || targetWindowingMode == WINDOWING_MODE_FREEFORM;
- }
-
void touchActiveTime() {
lastActiveTime = SystemClock.elapsedRealtime();
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 2b848d57e2f9..0b9ceeaf5d4e 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -163,14 +163,6 @@ class WallpaperController {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen()
+ " mDrawState=" + w.mWinAnimator.mDrawState);
- if (w.mWillReplaceWindow && mWallpaperTarget == null
- && !mFindResults.useTopWallpaperAsTarget) {
- // When we are replacing a window and there was wallpaper before replacement, we want to
- // keep the window until the new windows fully appear and can determine the visibility,
- // to avoid flickering.
- mFindResults.setUseTopWallpaperAsTarget(true);
- }
-
final WindowContainer animatingContainer = w.mActivityRecord != null
? w.mActivityRecord.getAnimatingContainer() : null;
final boolean keyguardGoingAwayWithWallpaper = (animatingContainer != null
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index c11391e1236e..25965331241e 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -69,10 +69,6 @@ public class WindowAnimator {
SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2);
private boolean mInitialized = false;
- // When set to true the animator will go over all windows after an animation frame is posted and
- // check if some got replaced and can be removed.
- private boolean mRemoveReplacedWindows = false;
-
private Choreographer mChoreographer;
/**
@@ -217,11 +213,6 @@ public class WindowAnimator {
mService.closeSurfaceTransaction("WindowAnimator");
ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate");
- if (mRemoveReplacedWindows) {
- root.removeReplacedWindows();
- mRemoveReplacedWindows = false;
- }
-
mService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
executeAfterPrepareSurfacesRunnables();
@@ -286,10 +277,6 @@ public class WindowAnimator {
return displayAnimator;
}
- void requestRemovalOfReplacedWindows(WindowState win) {
- mRemoveReplacedWindows = true;
- }
-
void scheduleAnimation() {
if (!mAnimationFrameCallbackScheduled) {
mAnimationFrameCallbackScheduled = true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 42d23e755b21..be42f36f7d30 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -88,7 +88,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManager.TRANSIT_RELAUNCH;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.fixScale;
import static android.view.WindowManagerGlobal.ADD_OKAY;
@@ -382,9 +381,6 @@ public class WindowManagerService extends IWindowManager.Stub
/** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */
static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000;
- /** Amount of time (in milliseconds) to delay before declaring a window replacement timeout. */
- static final int WINDOW_REPLACEMENT_TIMEOUT_DURATION = 2000;
-
/** Amount of time to allow a last ANR message to exist before freeing the memory. */
static final int LAST_ANR_LIFETIME_DURATION_MSECS = 2 * 60 * 60 * 1000; // Two hours
@@ -565,12 +561,6 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowManagerGlobalLock mGlobalLock;
/**
- * List of app window tokens that are waiting for replacing windows. If the
- * replacement doesn't come in time the stale windows needs to be disposed of.
- */
- final ArrayList<ActivityRecord> mWindowReplacementTimeouts = new ArrayList<>();
-
- /**
* Windows that are being resized. Used so we can tell the client about
* the resize after closing the transaction in which we resized the
* underlying surface.
@@ -1774,15 +1764,6 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowStateAnimator winAnimator = win.mWinAnimator;
winAnimator.mEnterAnimationPending = true;
winAnimator.mEnteringAnimation = true;
- // Check if we need to prepare a transition for replacing window first.
- if (!win.mTransitionController.isShellTransitionsEnabled()
- && activity != null && activity.isVisible()
- && !prepareWindowReplacementTransition(activity)) {
- // If not, check if need to set up a dummy transition during display freeze
- // so that the unfreeze wait for the apps to draw. This might be needed if
- // the app is relaunching.
- prepareNoneTransitionForRelaunching(activity);
- }
if (displayPolicy.areSystemBarsForcedConsumedLw()) {
res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
@@ -1944,48 +1925,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
/**
- * Returns true if we're done setting up any transitions.
- */
- private boolean prepareWindowReplacementTransition(ActivityRecord activity) {
- activity.clearAllDrawn();
- final WindowState replacedWindow = activity.getReplacingWindow();
- if (replacedWindow == null) {
- // We expect to already receive a request to remove the old window. If it did not
- // happen, let's just simply add a window.
- return false;
- }
- // We use the visible frame, because we want the animation to morph the window from what
- // was visible to the user to the final destination of the new window.
- final Rect frame = new Rect(replacedWindow.getFrame());
- final WindowManager.LayoutParams attrs = replacedWindow.mAttrs;
- frame.inset(replacedWindow.getInsetsStateWithVisibilityOverride().calculateVisibleInsets(
- frame, attrs.type, replacedWindow.getWindowingMode(), attrs.softInputMode,
- attrs.flags));
- // We treat this as if this activity was opening, so we can trigger the app transition
- // animation and piggy-back on existing transition animation infrastructure.
- final DisplayContent dc = activity.getDisplayContent();
- dc.mOpeningApps.add(activity);
- dc.prepareAppTransition(TRANSIT_RELAUNCH);
- dc.mAppTransition.overridePendingAppTransitionClipReveal(frame.left, frame.top,
- frame.width(), frame.height());
- dc.executeAppTransition();
- return true;
- }
-
- private void prepareNoneTransitionForRelaunching(ActivityRecord activity) {
- // Set up a none-transition and add the app to opening apps, so that the display
- // unfreeze wait for the apps to be drawn.
- // Note that if the display unfroze already because app unfreeze timed out,
- // we don't set up the transition anymore and just let it go.
- final DisplayContent dc = activity.getDisplayContent();
- if (mDisplayFrozen && !dc.mOpeningApps.contains(activity) && activity.isRelaunching()) {
- dc.mOpeningApps.add(activity);
- dc.prepareAppTransition(TRANSIT_NONE);
- dc.executeAppTransition();
- }
- }
-
- /**
* Set whether screen capture is disabled for all windows of a specific user from
* the device policy cache.
*/
@@ -2390,12 +2329,6 @@ public class WindowManagerService extends IWindowManager.Stub
// If we are not currently running the exit animation, we need to see about starting
// one.
- // We don't want to animate visibility of windows which are pending replacement.
- // In the case of activity relaunch child windows could request visibility changes as
- // they are detached from the main application window during the tear down process.
- // If we satisfied these visibility changes though, we would cause a visual glitch
- // hiding the window before it's replacement was available. So we just do nothing on
- // our side.
// This must be called before the call to performSurfacePlacement.
if (!shouldRelayout && winAnimator.hasSurface() && !win.mAnimatingExit) {
if (DEBUG_VISIBILITY) {
@@ -2403,20 +2336,18 @@ public class WindowManagerService extends IWindowManager.Stub
"Relayout invis " + win + ": mAnimatingExit=" + win.mAnimatingExit);
}
result |= RELAYOUT_RES_SURFACE_CHANGED;
- if (!win.mWillReplaceWindow) {
- // When FLAG_SHOW_WALLPAPER flag is removed from a window, we usually set a flag
- // in DC#pendingLayoutChanges and update the wallpaper target later.
- // However it's possible that FLAG_SHOW_WALLPAPER flag is removed from a window
- // when the window is about to exit, so we update the wallpaper target
- // immediately here. Otherwise this window will be stuck in exiting and its
- // surface remains on the screen.
- // TODO(b/189856716): Allow destroying surface even if it belongs to the
- // keyguard target.
- if (wallpaperMayMove) {
- displayContent.mWallpaperController.adjustWallpaperWindows();
- }
- tryStartExitingAnimation(win, winAnimator);
+ // When FLAG_SHOW_WALLPAPER flag is removed from a window, we usually set a flag
+ // in DC#pendingLayoutChanges and update the wallpaper target later.
+ // However it's possible that FLAG_SHOW_WALLPAPER flag is removed from a window
+ // when the window is about to exit, so we update the wallpaper target
+ // immediately here. Otherwise this window will be stuck in exiting and its
+ // surface remains on the screen.
+ // TODO(b/189856716): Allow destroying surface even if it belongs to the
+ // keyguard target.
+ if (wallpaperMayMove) {
+ displayContent.mWallpaperController.adjustWallpaperWindows();
}
+ tryStartExitingAnimation(win, winAnimator);
}
// Create surfaceControl before surface placement otherwise layout will be skipped
@@ -5328,8 +5259,6 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int UPDATE_MULTI_WINDOW_STACKS = 41;
- public static final int WINDOW_REPLACEMENT_TIMEOUT = 46;
-
public static final int UPDATE_ANIMATION_SCALE = 51;
public static final int WINDOW_HIDE_TIMEOUT = 52;
public static final int RESTORE_POINTER_ICON = 55;
@@ -5555,16 +5484,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
break;
}
- case WINDOW_REPLACEMENT_TIMEOUT: {
- synchronized (mGlobalLock) {
- for (int i = mWindowReplacementTimeouts.size() - 1; i >= 0; i--) {
- final ActivityRecord activity = mWindowReplacementTimeouts.get(i);
- activity.onWindowReplacementTimeout();
- }
- mWindowReplacementTimeouts.clear();
- }
- break;
- }
case WINDOW_HIDE_TIMEOUT: {
final WindowState window = (WindowState) msg.obj;
synchronized (mGlobalLock) {
@@ -7083,98 +7002,6 @@ public class WindowManagerService extends IWindowManager.Stub
return mGlobalLock;
}
- /**
- * Hint to a token that its activity will relaunch, which will trigger removal and addition of
- * a window.
- *
- * @param token Application token for which the activity will be relaunched.
- */
- void setWillReplaceWindow(IBinder token, boolean animate) {
- final ActivityRecord activity = mRoot.getActivityRecord(token);
- if (activity == null) {
- ProtoLog.w(WM_ERROR, "Attempted to set replacing window on non-existing app token %s",
- token);
- return;
- }
- if (!activity.hasContentToDisplay()) {
- ProtoLog.w(WM_ERROR,
- "Attempted to set replacing window on app token with no content %s",
- token);
- return;
- }
- activity.setWillReplaceWindows(animate);
- }
-
- /**
- * Hint to a token that its windows will be replaced across activity relaunch.
- * The windows would otherwise be removed shortly following this as the
- * activity is torn down.
- * @param token Application token for which the activity will be relaunched.
- * @param childrenOnly Whether to mark only child windows for replacement
- * (for the case where main windows are being preserved/
- * reused rather than replaced).
- *
- */
- // TODO: The s at the end of the method name is the only difference with the name of the method
- // above. We should combine them or find better names.
- void setWillReplaceWindows(IBinder token, boolean childrenOnly) {
- synchronized (mGlobalLock) {
- final ActivityRecord activity = mRoot.getActivityRecord(token);
- if (activity == null) {
- ProtoLog.w(WM_ERROR,
- "Attempted to set replacing window on non-existing app token %s",
- token);
- return;
- }
- if (!activity.hasContentToDisplay()) {
- ProtoLog.w(WM_ERROR,
- "Attempted to set replacing window on app token with no content %s",
- token);
- return;
- }
-
- if (childrenOnly) {
- activity.setWillReplaceChildWindows();
- } else {
- activity.setWillReplaceWindows(false /* animate */);
- }
-
- scheduleClearWillReplaceWindows(token, true /* replacing */);
- }
- }
-
- /**
- * If we're replacing the window, schedule a timer to clear the replaced window
- * after a timeout, in case the replacing window is not coming.
- *
- * If we're not replacing the window, clear the replace window settings of the app.
- *
- * @param token Application token for the activity whose window might be replaced.
- * @param replacing Whether the window is being replaced or not.
- */
- void scheduleClearWillReplaceWindows(IBinder token, boolean replacing) {
- final ActivityRecord activity = mRoot.getActivityRecord(token);
- if (activity == null) {
- ProtoLog.w(WM_ERROR, "Attempted to reset replacing window on non-existing app token %s",
- token);
- return;
- }
- if (replacing) {
- scheduleWindowReplacementTimeouts(activity);
- } else {
- activity.clearWillReplaceWindows();
- }
- }
-
- void scheduleWindowReplacementTimeouts(ActivityRecord activity) {
- if (!mWindowReplacementTimeouts.contains(activity)) {
- mWindowReplacementTimeouts.add(activity);
- }
- mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
- mH.sendEmptyMessageDelayed(
- H.WINDOW_REPLACEMENT_TIMEOUT, WINDOW_REPLACEMENT_TIMEOUT_DURATION);
- }
-
@Override
public int getDockedStackSide() {
return 0;
@@ -8744,8 +8571,8 @@ public class WindowManagerService extends IWindowManager.Stub
*/
void grantInputChannel(Session session, int callingUid, int callingPid, int displayId,
SurfaceControl surface, IWindow window, IBinder hostInputToken,
- int flags, int privateFlags, int type, IBinder windowToken, IBinder focusGrantToken,
- String inputHandleName, InputChannel outInputChannel) {
+ int flags, int privateFlags, int inputFeatures, int type, IBinder windowToken,
+ IBinder focusGrantToken, String inputHandleName, InputChannel outInputChannel) {
final int sanitizedType = sanitizeWindowType(session, displayId, windowToken, type);
final InputApplicationHandle applicationHandle;
final String name;
@@ -8762,7 +8589,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
- name, applicationHandle, flags, privateFlags, sanitizedType,
+ name, applicationHandle, flags, privateFlags, inputFeatures, sanitizedType,
null /* region */, window);
clientChannel.copyTo(outInputChannel);
@@ -8803,13 +8630,14 @@ public class WindowManagerService extends IWindowManager.Stub
private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,
int displayId, SurfaceControl surface, String name,
InputApplicationHandle applicationHandle, int flags,
- int privateFlags, int type, Region region, IWindow window) {
+ int privateFlags, int inputFeatures, int type, Region region, IWindow window) {
final InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId);
h.token = channelToken;
h.setWindowToken(window);
h.name = name;
flags = sanitizeFlagSlippery(flags, name, callingUid, callingPid);
+ inputFeatures = sanitizeSpyWindow(inputFeatures, name, callingUid, callingPid);
final int sanitizedLpFlags =
(flags & (FLAG_NOT_TOUCHABLE | FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE))
@@ -8819,7 +8647,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Do not allow any input features to be set without sanitizing them first.
h.inputConfig = InputConfigAdapter.getInputConfigFromWindowParams(
- type, sanitizedLpFlags, 0 /*inputFeatures*/);
+ type, sanitizedLpFlags, inputFeatures);
if ((flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0) {
@@ -8856,7 +8684,7 @@ public class WindowManagerService extends IWindowManager.Stub
* is undefined.
*/
void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
- int flags, int privateFlags, Region region) {
+ int flags, int privateFlags, int inputFeatures, Region region) {
final InputApplicationHandle applicationHandle;
final String name;
final EmbeddedWindowController.EmbeddedWindow win;
@@ -8871,7 +8699,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
updateInputChannel(channelToken, win.mOwnerUid, win.mOwnerPid, displayId, surface, name,
- applicationHandle, flags, privateFlags, win.mWindowType, region, win.mClient);
+ applicationHandle, flags, privateFlags, inputFeatures, win.mWindowType, region,
+ win.mClient);
}
/** Return whether layer tracing is enabled */
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d6c03113e87f..8a083aa6220f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -59,13 +59,11 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NOT_MAGNIFIAB
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
@@ -632,22 +630,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
boolean mHasSurface = false;
- // This window will be replaced due to relaunch. This allows window manager
- // to differentiate between simple removal of a window and replacement. In the latter case it
- // will preserve the old window until the new one is drawn.
- boolean mWillReplaceWindow = false;
- // If true, the replaced window was already requested to be removed.
- private boolean mReplacingRemoveRequested = false;
- // Whether the replacement of the window should trigger app transition animation.
- private boolean mAnimateReplacingWindow = false;
- // If not null, the window that will be used to replace the old one. This is being set when
- // the window is added and unset when this window reports its first draw.
- private WindowState mReplacementWindow = null;
- // For the new window in the replacement transition, if we have
- // requested to replace without animation, then we should
- // make sure we also don't apply an enter animation for
- // the new window.
- boolean mSkipEnterAnimationForSeamlessReplacement = false;
// Whether this window is being moved via the resize API
private boolean mMovedByResize;
@@ -1309,13 +1291,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
boolean skipLayout() {
- if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
- // This window is being replaced and either already got information that it's being
- // removed or we are still waiting for some information. Because of this we don't
- // want to apply any more changes to it, so it remains in this state until new window
- // appears.
- return true;
- }
// Skip layout of the window when in transition to pip mode.
return mActivityRecord != null && mActivityRecord.mWaitForEnteringPinnedMode;
}
@@ -2354,24 +2329,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- void onWindowReplacementTimeout() {
- if (mWillReplaceWindow) {
- // Since the window already timed out, remove it immediately now.
- // Use WindowState#removeImmediately() instead of WindowState#removeIfPossible(), as
- // the latter delays removal on certain conditions, which will leave the stale window
- // in the root task and marked mWillReplaceWindow=false, so the window will never be
- // removed.
- //
- // Also removes child windows.
- removeImmediately();
- } else {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- c.onWindowReplacementTimeout();
- }
- }
- }
-
@Override
void removeImmediately() {
if (mRemoved) {
@@ -2388,11 +2345,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWinAnimator.destroySurfaceLocked(getSyncTransaction());
super.removeImmediately();
- mWillReplaceWindow = false;
- if (mReplacementWindow != null) {
- mReplacementWindow.mSkipEnterAnimationForSeamlessReplacement = false;
- }
-
final DisplayContent dc = getDisplayContent();
if (isImeLayeringTarget()) {
// Remove the attached IME screenshot surface.
@@ -2472,12 +2424,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b "
+ "mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b "
- + "mWillReplaceWindow=%b mDisplayFrozen=%b callers=%s",
+ + "mDisplayFrozen=%b callers=%s",
this, mWinAnimator.mSurfaceController, mAnimatingExit, mRemoveOnExit,
mHasSurface, mWinAnimator.getShown(),
isAnimating(TRANSITION | PARENTS),
mActivityRecord != null && mActivityRecord.isAnimating(PARENTS | TRANSITION),
- mWillReplaceWindow,
mWmService.mDisplayFrozen, Debug.getCallers(6));
// Visibility of the removed window. Will be used later to update orientation later on.
@@ -2487,22 +2438,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// window until the animation is done. If the display is frozen, just remove immediately,
// since the animation wouldn't be seen.
if (mHasSurface && mToken.okToAnimate()) {
- if (mWillReplaceWindow) {
- // This window is going to be replaced. We need to keep it around until the new one
- // gets added, then we will get rid of this one.
- ProtoLog.v(WM_DEBUG_ADD_REMOVE,
- "Preserving %s until the new one is added", this);
- // TODO: We are overloading mAnimatingExit flag to prevent the window state from
- // been removed. We probably need another flag to indicate that window removal
- // should be deffered vs. overloading the flag that says we are playing an exit
- // animation.
- ProtoLog.v(WM_DEBUG_ANIM,
- "Set animatingExit: reason=remove/replaceWindow win=%s", this);
- mAnimatingExit = true;
- mReplacingRemoveRequested = true;
- return;
- }
-
// If we are not currently running the exit animation, we need to see about starting one
wasVisible = isVisible();
@@ -2714,53 +2649,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mInputWindowHandle.setToken(null);
}
- /** Returns true if the replacement window was removed. */
- boolean removeReplacedWindowIfNeeded(WindowState replacement) {
- if (mWillReplaceWindow && mReplacementWindow == replacement && replacement.hasDrawn()) {
- replacement.mSkipEnterAnimationForSeamlessReplacement = false;
- removeReplacedWindow();
- return true;
- }
-
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- if (c.removeReplacedWindowIfNeeded(replacement)) {
- return true;
- }
- }
- return false;
- }
-
- private void removeReplacedWindow() {
- ProtoLog.d(WM_DEBUG_ADD_REMOVE, "Removing replaced window: %s", this);
- mWillReplaceWindow = false;
- mAnimateReplacingWindow = false;
- mReplacingRemoveRequested = false;
- mReplacementWindow = null;
- if (mAnimatingExit || !mAnimateReplacingWindow) {
- removeImmediately();
- }
- }
-
- boolean setReplacementWindowIfNeeded(WindowState replacementCandidate) {
- boolean replacementSet = false;
-
- if (mWillReplaceWindow && mReplacementWindow == null
- && getWindowTag().toString().equals(replacementCandidate.getWindowTag().toString())) {
-
- mReplacementWindow = replacementCandidate;
- replacementCandidate.mSkipEnterAnimationForSeamlessReplacement = !mAnimateReplacingWindow;
- replacementSet = true;
- }
-
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- replacementSet |= c.setReplacementWindowIfNeeded(replacementCandidate);
- }
-
- return replacementSet;
- }
-
void setDisplayLayoutNeeded() {
final DisplayContent dc = getDisplayContent();
if (dc != null) {
@@ -4391,49 +4279,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return parent != null && parent.isGoneForLayout();
}
- void setWillReplaceWindow(boolean animate) {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState c = mChildren.get(i);
- c.setWillReplaceWindow(animate);
- }
-
- if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) != 0
- || mAttrs.type == TYPE_APPLICATION_STARTING) {
- // We don't set replacing on starting windows since they are added by window manager and
- // not the client so won't be replaced by the client.
- return;
- }
-
- mWillReplaceWindow = true;
- mReplacementWindow = null;
- mAnimateReplacingWindow = animate;
- }
-
- void clearWillReplaceWindow() {
- mWillReplaceWindow = false;
- mReplacementWindow = null;
- mAnimateReplacingWindow = false;
-
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState c = mChildren.get(i);
- c.clearWillReplaceWindow();
- }
- }
-
- boolean waitingForReplacement() {
- if (mWillReplaceWindow) {
- return true;
- }
-
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState c = mChildren.get(i);
- if (c.waitingForReplacement()) {
- return true;
- }
- }
- return false;
- }
-
void requestUpdateWallpaperIfNeeded() {
final DisplayContent dc = getDisplayContent();
if (dc != null && ((mIsWallpaper && !mLastConfigReportedToClient) || hasWallpaper())) {
@@ -4464,43 +4309,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return winY;
}
- // During activity relaunch due to resize, we sometimes use window replacement
- // for only child windows (as the main window is handled by window preservation)
- // and the big surface.
- //
- // Though windows of TYPE_APPLICATION or TYPE_DRAWN_APPLICATION (as opposed to
- // TYPE_BASE_APPLICATION) are not children in the sense of an attached window,
- // we also want to replace them at such phases, as they won't be covered by window
- // preservation, and in general we expect them to return following relaunch.
- boolean shouldBeReplacedWithChildren() {
- return mIsChildWindow || mAttrs.type == TYPE_APPLICATION
- || mAttrs.type == TYPE_DRAWN_APPLICATION;
- }
-
- void setWillReplaceChildWindows() {
- if (shouldBeReplacedWithChildren()) {
- setWillReplaceWindow(false /* animate */);
- }
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState c = mChildren.get(i);
- c.setWillReplaceChildWindows();
- }
- }
-
- WindowState getReplacingWindow() {
- if (mAnimatingExit && mWillReplaceWindow && mAnimateReplacingWindow) {
- return this;
- }
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState c = mChildren.get(i);
- final WindowState replacing = c.getReplacingWindow();
- if (replacing != null) {
- return replacing;
- }
- }
- return null;
- }
-
int getRotationAnimationHint() {
if (mActivityRecord != null) {
return mActivityRecord.mRotationAnimationHint;
@@ -4990,14 +4798,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
boolean clearAnimatingFlags() {
boolean didSomething = false;
- // We don't want to clear it out for windows that get replaced, because the
- // animation depends on the flag to remove the replaced window.
- //
// We also don't clear the mAnimatingExit flag for windows which have the
// mRemoveOnExit flag. This indicates an explicit remove request has been issued
// by the client. We should let animation proceed and not clear this flag or
// they won't eventually be removed by WindowStateAnimator#finishExit.
- if (!mWillReplaceWindow && !mRemoveOnExit) {
+ if (!mRemoveOnExit) {
// Clear mAnimating flag together with mAnimatingExit. When animation
// changes from exiting to entering, we need to clear this flag until the
// new animation gets applied, so that isAnimationStarting() becomes true
@@ -5312,7 +5117,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return activity.needsZBoost();
}
}
- return mWillReplaceWindow;
+ return false;
}
private boolean isStartingWindowAssociatedToTask() {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index e8625bc3d64b..3aac816fcd7a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -449,7 +449,6 @@ class WindowStateAnimator {
if (prepared && mDrawState == HAS_DRAWN) {
if (mLastHidden) {
mSurfaceController.showRobustly(t);
- mAnimator.requestRemovalOfReplacedWindows(w);
mLastHidden = false;
final DisplayContent displayContent = w.getDisplayContent();
if (!displayContent.getLastHasContent()) {
@@ -504,13 +503,6 @@ class WindowStateAnimator {
}
void applyEnterAnimationLocked() {
- // If we are the new part of a window replacement transition and we have requested
- // not to animate, we instead want to make it seamless, so we don't want to apply
- // an enter transition.
- if (mWin.mSkipEnterAnimationForSeamlessReplacement) {
- return;
- }
-
final int transit;
if (mEnterAnimationPending) {
mEnterAnimationPending = false;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index c6b78982169c..327483ebbef7 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -315,17 +315,6 @@ class WindowToken extends WindowContainer<WindowState> {
return mChildren.isEmpty();
}
- WindowState getReplacingWindow() {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState win = mChildren.get(i);
- final WindowState replacing = win.getReplacingWindow();
- if (replacing != null) {
- return replacing;
- }
- }
- return null;
- }
-
/** Return true if this token has a window that wants the wallpaper displayed behind it. */
boolean windowsCanBeWallpaperTarget() {
for (int j = mChildren.size() - 1; j >= 0; j--) {
diff --git a/services/core/jni/gnss/GnssConfiguration.cpp b/services/core/jni/gnss/GnssConfiguration.cpp
index 3677641127f3..b57e451264a4 100644
--- a/services/core/jni/gnss/GnssConfiguration.cpp
+++ b/services/core/jni/gnss/GnssConfiguration.cpp
@@ -67,7 +67,7 @@ GnssConfiguration::GnssConfiguration(const sp<IGnssConfiguration>& iGnssConfigur
: mIGnssConfiguration(iGnssConfiguration) {}
jobject GnssConfiguration::getVersion(JNIEnv* env) {
- return createHalInterfaceVersionJavaObject(env, 3, 0);
+ return createHalInterfaceVersionJavaObject(env, 3, mIGnssConfiguration->getInterfaceVersion());
}
jboolean GnssConfiguration::setEmergencySuplPdn(jint enable) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a1789b2b125d..321924c79c58 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -95,6 +95,7 @@ import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDG
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
+import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_FINANCING_STATE_CHANGED;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
@@ -15440,7 +15441,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Slogf.i(LOG_TAG, "Sending %s broadcast to manifest receivers.", intent.getAction());
broadcastIntentToCrossProfileManifestReceivers(
intent, parentHandle, requiresPermission);
- broadcastIntentToDevicePolicyManagerRoleHolder(intent, parentHandle);
+ broadcastExplicitIntentToRoleHolder(
+ intent, RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT, parentHandle);
}
@Override
@@ -15481,36 +15483,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- private void broadcastIntentToDevicePolicyManagerRoleHolder(
- Intent intent, UserHandle userHandle) {
- final int userId = userHandle.getIdentifier();
- final String packageName = getDevicePolicyManagementRoleHolderPackageName(mContext);
- if (packageName == null) {
- return;
- }
- try {
- final Intent packageIntent = new Intent(intent)
- .setPackage(packageName);
- final List<ResolveInfo> receivers = mIPackageManager.queryIntentReceivers(
- packageIntent,
- /* resolvedType= */ null,
- STOCK_PM_FLAGS,
- userId).getList();
- if (receivers.isEmpty()) {
- return;
- }
- for (ResolveInfo receiver : receivers) {
- final Intent componentIntent = new Intent(packageIntent)
- .setComponent(receiver.getComponentInfo().getComponentName())
- .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- mContext.sendBroadcastAsUser(componentIntent, userHandle);
- }
- } catch (RemoteException ex) {
- Slogf.w(LOG_TAG, "Cannot get list of broadcast receivers for %s because: %s.",
- intent.getAction(), ex);
- }
- }
-
/**
* Checks whether the package {@code packageName} has the {@code MODIFY_QUIET_MODE}
* permission granted for the user {@code userId}.
@@ -20718,7 +20690,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void maybeInstallDevicePolicyManagementRoleHolderInUser(int targetUserId) {
String devicePolicyManagerRoleHolderPackageName =
- getDevicePolicyManagementRoleHolderPackageName(mContext);
+ getRoleHolderPackageName(mContext, RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT);
if (devicePolicyManagerRoleHolderPackageName == null) {
Slogf.d(LOG_TAG, "No device policy management role holder specified.");
return;
@@ -20744,14 +20716,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ /**
+ * If multiple packages hold the role, returns the first package in the list.
+ */
+ @Nullable
+ private String getRoleHolderPackageName(Context context, String role) {
+ return getRoleHolderPackageNameOnUser(context, role, Process.myUserHandle());
+ }
- private String getDevicePolicyManagementRoleHolderPackageName(Context context) {
+ /**
+ * If multiple packages hold the role, returns the first package in the list.
+ */
+ @Nullable
+ private String getRoleHolderPackageNameOnUser(Context context, String role, UserHandle user) {
RoleManager roleManager = context.getSystemService(RoleManager.class);
// Calling identity needs to be cleared as this method is used in the permissions checks.
return mInjector.binderWithCleanCallingIdentity(() -> {
- List<String> roleHolders =
- roleManager.getRoleHolders(RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT);
+ List<String> roleHolders = roleManager.getRoleHoldersAsUser(role, user);
if (roleHolders.isEmpty()) {
return null;
}
@@ -20762,7 +20744,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private boolean isCallerDevicePolicyManagementRoleHolder(CallerIdentity caller) {
int callerUid = caller.getUid();
String devicePolicyManagementRoleHolderPackageName =
- getDevicePolicyManagementRoleHolderPackageName(mContext);
+ getRoleHolderPackageName(mContext, RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT);
int roleHolderUid = mInjector.getPackageManagerInternal().getPackageUid(
devicePolicyManagementRoleHolderPackageName, 0, caller.getUserId());
@@ -21830,15 +21812,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
public void register() {
- mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.SYSTEM);
+ mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
}
@Override
public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
- if (!RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT.equals(roleName)) {
+ if (RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT.equals(roleName)) {
+ handleDevicePolicyManagementRoleChange(user);
+ return;
+ }
+ if (RoleManager.ROLE_FINANCED_DEVICE_KIOSK.equals(roleName)) {
+ handleFinancedDeviceKioskRoleChange();
return;
}
- String newRoleHolder = getRoleHolder();
+ }
+
+ private void handleDevicePolicyManagementRoleChange(UserHandle user) {
+ String newRoleHolder = getDeviceManagementRoleHolder(user);
if (isDefaultRoleHolder(newRoleHolder)) {
Slogf.i(LOG_TAG,
"onRoleHoldersChanged: Default role holder is set, returning early");
@@ -21873,9 +21863,44 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- private String getRoleHolder() {
- return DevicePolicyManagerService.this.getDevicePolicyManagementRoleHolderPackageName(
- mContext);
+ private void handleFinancedDeviceKioskRoleChange() {
+ if (!isDevicePolicyEngineEnabled()) {
+ return;
+ }
+ Slog.i(LOG_TAG, "Handling action " + ACTION_DEVICE_FINANCING_STATE_CHANGED);
+ Intent intent = new Intent(ACTION_DEVICE_FINANCING_STATE_CHANGED);
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ for (UserInfo userInfo : mUserManager.getUsers()) {
+ UserHandle user = userInfo.getUserHandle();
+ broadcastExplicitIntentToRoleHolder(
+ intent, RoleManager.ROLE_SYSTEM_SUPERVISION, user);
+ broadcastExplicitIntentToRoleHolder(
+ intent, RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT, user);
+ ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(user.getIdentifier());
+ if (admin == null) {
+ continue;
+ }
+ if (!isProfileOwnerOfOrganizationOwnedDevice(
+ admin.info.getComponent(), user.getIdentifier())
+ && !isDeviceOwner(admin)
+ && !(isProfileOwner(admin.info.getComponent(), user.getIdentifier())
+ && admin.getUserHandle().isSystem())) {
+ continue;
+ }
+ // Don't send the broadcast twice if the DPC is the same package as the
+ // DMRH
+ if (admin.info.getPackageName().equals(getDeviceManagementRoleHolder(user))) {
+ continue;
+ }
+ broadcastExplicitIntentToPackage(
+ intent, admin.info.getPackageName(), admin.getUserHandle());
+ }
+ });
+ }
+
+ private String getDeviceManagementRoleHolder(UserHandle user) {
+ return DevicePolicyManagerService.this.getRoleHolderPackageNameOnUser(
+ mContext, RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT, user);
}
private boolean isDefaultRoleHolder(String packageName) {
@@ -21935,6 +21960,40 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ private void broadcastExplicitIntentToRoleHolder(
+ Intent intent, String role, UserHandle userHandle) {
+ String packageName = getRoleHolderPackageNameOnUser(mContext, role, userHandle);
+ if (packageName == null) {
+ return;
+ }
+ broadcastExplicitIntentToPackage(intent, packageName, userHandle);
+ }
+
+ private void broadcastExplicitIntentToPackage(
+ Intent intent, String packageName, UserHandle userHandle) {
+ int userId = userHandle.getIdentifier();
+ if (packageName == null) {
+ return;
+ }
+ Intent packageIntent = new Intent(intent)
+ .setPackage(packageName);
+ List<ResolveInfo> receivers = mContext.getPackageManager().queryBroadcastReceiversAsUser(
+ packageIntent,
+ PackageManager.ResolveInfoFlags.of(PackageManager.GET_RECEIVERS),
+ userId);
+ if (receivers.isEmpty()) {
+ Slog.i(LOG_TAG, "Found no receivers to handle intent " + intent
+ + " in package " + packageName);
+ return;
+ }
+ for (ResolveInfo receiver : receivers) {
+ Intent componentIntent = new Intent(packageIntent)
+ .setComponent(receiver.getComponentInfo().getComponentName())
+ .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ mContext.sendBroadcastAsUser(componentIntent, userHandle);
+ }
+ }
+
@Override
public List<UserHandle> getPolicyManagedProfiles(@NonNull UserHandle user) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index 1ced95b92aa4..51dcc0323a96 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -148,6 +148,8 @@ public final class DisplayPowerController2Test {
mCdsiMock).when(() -> LocalServices.getService(
ColorDisplayService.ColorDisplayServiceInternal.class));
doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService);
+ doAnswer((Answer<Boolean>) invocationOnMock -> true).when(() ->
+ Settings.System.putFloatForUser(any(), any(), anyFloat(), anyInt()));
setUpSensors();
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
@@ -287,73 +289,6 @@ public final class DisplayPowerController2Test {
eq(mProxSensor), anyInt(), any(Handler.class));
}
- /**
- * Creates a mock and registers it to {@link LocalServices}.
- */
- private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
- LocalServices.removeServiceForTest(clazz);
- LocalServices.addService(clazz, mock);
- }
-
- private void advanceTime(long timeMs) {
- mClock.fastForward(timeMs);
- mTestLooper.dispatchAll();
- }
-
- private void setUpSensors() throws Exception {
- mProxSensor = TestUtils.createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY,
- PROX_SENSOR_MAX_RANGE);
- Sensor screenOffBrightnessSensor = TestUtils.createSensor(
- Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
- when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL)))
- .thenReturn(List.of(mProxSensor, screenOffBrightnessSensor));
- }
-
- private SensorEventListener getSensorEventListener(Sensor sensor) {
- verify(mSensorManagerMock).registerListener(mSensorEventListenerCaptor.capture(),
- eq(sensor), eq(SensorManager.SENSOR_DELAY_NORMAL), isA(Handler.class));
- return mSensorEventListenerCaptor.getValue();
- }
-
- private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock,
- DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock,
- boolean isEnabled) {
- DisplayInfo info = new DisplayInfo();
- DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
- deviceInfo.uniqueId = uniqueId;
-
- when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
- when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock);
- when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
- when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
- when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
- when(logicalDisplayMock.getBrightnessThrottlingDataIdLocked()).thenReturn(
- DisplayDeviceConfig.DEFAULT_ID);
- when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
- when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
- when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock);
- when(displayDeviceConfigMock.getProximitySensor()).thenReturn(
- new DisplayDeviceConfig.SensorData() {
- {
- type = Sensor.STRING_TYPE_PROXIMITY;
- name = null;
- }
- });
- when(displayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500});
- when(displayDeviceConfigMock.isAutoBrightnessAvailable()).thenReturn(true);
- when(displayDeviceConfigMock.getAmbientLightSensor()).thenReturn(
- new DisplayDeviceConfig.SensorData());
- when(displayDeviceConfigMock.getScreenOffBrightnessSensor()).thenReturn(
- new DisplayDeviceConfig.SensorData() {
- {
- type = Sensor.STRING_TYPE_LIGHT;
- name = null;
- }
- });
- when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux())
- .thenReturn(new int[0]);
- }
-
@Test
public void testDisplayBrightnessFollowers_BothDpcsSupportNits() {
DisplayPowerControllerHolder followerDpc =
@@ -482,6 +417,32 @@ public final class DisplayPowerController2Test {
verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
}
+ @Test
+ public void testDisplayBrightnessFollowers_AutomaticBrightness() {
+ doAnswer((Answer<Integer>) invocationOnMock ->
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC)
+ .when(() -> Settings.System.getIntForUser(any(ContentResolver.class),
+ eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(),
+ eq(UserHandle.USER_CURRENT)));
+ final float brightness = 0.4f;
+ final float nits = 300;
+ final float ambientLux = 3000;
+ when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness())
+ .thenReturn(brightness);
+ when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness())
+ .thenReturn(0.3f);
+ when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
+ when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ DisplayPowerController followerDpc = mock(DisplayPowerController.class);
+
+ mHolder.dpc.addDisplayBrightnessFollower(followerDpc);
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(followerDpc).setBrightnessToFollow(brightness, nits, ambientLux);
+ }
@Test
public void testDisplayBrightnessFollowersRemoval() {
@@ -750,6 +711,73 @@ public final class DisplayPowerController2Test {
verify(mHolder.animator, times(2)).animateTo(eq(newBrightness), anyFloat(), anyFloat());
}
+ /**
+ * Creates a mock and registers it to {@link LocalServices}.
+ */
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+
+ private void advanceTime(long timeMs) {
+ mClock.fastForward(timeMs);
+ mTestLooper.dispatchAll();
+ }
+
+ private void setUpSensors() throws Exception {
+ mProxSensor = TestUtils.createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY,
+ PROX_SENSOR_MAX_RANGE);
+ Sensor screenOffBrightnessSensor = TestUtils.createSensor(
+ Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
+ when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL)))
+ .thenReturn(List.of(mProxSensor, screenOffBrightnessSensor));
+ }
+
+ private SensorEventListener getSensorEventListener(Sensor sensor) {
+ verify(mSensorManagerMock).registerListener(mSensorEventListenerCaptor.capture(),
+ eq(sensor), eq(SensorManager.SENSOR_DELAY_NORMAL), isA(Handler.class));
+ return mSensorEventListenerCaptor.getValue();
+ }
+
+ private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock,
+ DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock,
+ boolean isEnabled) {
+ DisplayInfo info = new DisplayInfo();
+ DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
+ deviceInfo.uniqueId = uniqueId;
+
+ when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
+ when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock);
+ when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
+ when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
+ when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
+ when(logicalDisplayMock.getBrightnessThrottlingDataIdLocked()).thenReturn(
+ DisplayDeviceConfig.DEFAULT_ID);
+ when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
+ when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
+ when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock);
+ when(displayDeviceConfigMock.getProximitySensor()).thenReturn(
+ new DisplayDeviceConfig.SensorData() {
+ {
+ type = Sensor.STRING_TYPE_PROXIMITY;
+ name = null;
+ }
+ });
+ when(displayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500});
+ when(displayDeviceConfigMock.isAutoBrightnessAvailable()).thenReturn(true);
+ when(displayDeviceConfigMock.getAmbientLightSensor()).thenReturn(
+ new DisplayDeviceConfig.SensorData());
+ when(displayDeviceConfigMock.getScreenOffBrightnessSensor()).thenReturn(
+ new DisplayDeviceConfig.SensorData() {
+ {
+ type = Sensor.STRING_TYPE_LIGHT;
+ name = null;
+ }
+ });
+ when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux())
+ .thenReturn(new int[0]);
+ }
+
private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
String uniqueId) {
return createDisplayPowerController(displayId, uniqueId, /* isEnabled= */ true);
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
index 53fcdad30ed2..0a1bf1c9ed99 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -149,6 +149,8 @@ public final class DisplayPowerControllerTest {
mCdsiMock).when(() -> LocalServices.getService(
ColorDisplayService.ColorDisplayServiceInternal.class));
doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService);
+ doAnswer((Answer<Boolean>) invocationOnMock -> true).when(() ->
+ Settings.System.putFloatForUser(any(), any(), anyFloat(), anyInt()));
setUpSensors();
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
@@ -290,73 +292,6 @@ public final class DisplayPowerControllerTest {
eq(mProxSensor), anyInt(), any(Handler.class));
}
- /**
- * Creates a mock and registers it to {@link LocalServices}.
- */
- private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
- LocalServices.removeServiceForTest(clazz);
- LocalServices.addService(clazz, mock);
- }
-
- private void advanceTime(long timeMs) {
- mClock.fastForward(timeMs);
- mTestLooper.dispatchAll();
- }
-
- private void setUpSensors() throws Exception {
- mProxSensor = TestUtils.createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY,
- PROX_SENSOR_MAX_RANGE);
- Sensor screenOffBrightnessSensor = TestUtils.createSensor(
- Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
- when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL)))
- .thenReturn(List.of(mProxSensor, screenOffBrightnessSensor));
- }
-
- private SensorEventListener getSensorEventListener(Sensor sensor) {
- verify(mSensorManagerMock).registerListener(mSensorEventListenerCaptor.capture(),
- eq(sensor), eq(SensorManager.SENSOR_DELAY_NORMAL), isA(Handler.class));
- return mSensorEventListenerCaptor.getValue();
- }
-
- private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock,
- DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock,
- boolean isEnabled) {
- DisplayInfo info = new DisplayInfo();
- DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
- deviceInfo.uniqueId = uniqueId;
-
- when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
- when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock);
- when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
- when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
- when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
- when(logicalDisplayMock.getBrightnessThrottlingDataIdLocked()).thenReturn(
- DisplayDeviceConfig.DEFAULT_ID);
- when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
- when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
- when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock);
- when(displayDeviceConfigMock.getProximitySensor()).thenReturn(
- new DisplayDeviceConfig.SensorData() {
- {
- type = Sensor.STRING_TYPE_PROXIMITY;
- name = null;
- }
- });
- when(displayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500});
- when(displayDeviceConfigMock.isAutoBrightnessAvailable()).thenReturn(true);
- when(displayDeviceConfigMock.getAmbientLightSensor()).thenReturn(
- new DisplayDeviceConfig.SensorData());
- when(displayDeviceConfigMock.getScreenOffBrightnessSensor()).thenReturn(
- new DisplayDeviceConfig.SensorData() {
- {
- type = Sensor.STRING_TYPE_LIGHT;
- name = null;
- }
- });
- when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux())
- .thenReturn(new int[0]);
- }
-
@Test
public void testDisplayBrightnessFollowers_BothDpcsSupportNits() {
DisplayPowerControllerHolder followerDpc =
@@ -486,6 +421,33 @@ public final class DisplayPowerControllerTest {
}
@Test
+ public void testDisplayBrightnessFollowers_AutomaticBrightness() {
+ doAnswer((Answer<Integer>) invocationOnMock ->
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC)
+ .when(() -> Settings.System.getIntForUser(any(ContentResolver.class),
+ eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(),
+ eq(UserHandle.USER_CURRENT)));
+ final float brightness = 0.4f;
+ final float nits = 300;
+ final float ambientLux = 3000;
+ when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness())
+ .thenReturn(brightness);
+ when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness())
+ .thenReturn(0.3f);
+ when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
+ when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ DisplayPowerController followerDpc = mock(DisplayPowerController.class);
+
+ mHolder.dpc.addDisplayBrightnessFollower(followerDpc);
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(followerDpc).setBrightnessToFollow(brightness, nits, ambientLux);
+ }
+
+ @Test
public void testDisplayBrightnessFollowersRemoval() {
DisplayPowerControllerHolder followerHolder =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_DISPLAY_ID);
@@ -517,7 +479,6 @@ public final class DisplayPowerControllerTest {
verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness),
anyFloat(), anyFloat());
-
mHolder.dpc.addDisplayBrightnessFollower(followerHolder.dpc);
mHolder.dpc.addDisplayBrightnessFollower(secondFollowerHolder.dpc);
clearInvocations(followerHolder.animator);
@@ -754,6 +715,73 @@ public final class DisplayPowerControllerTest {
verify(mHolder.animator, times(2)).animateTo(eq(newBrightness), anyFloat(), anyFloat());
}
+ /**
+ * Creates a mock and registers it to {@link LocalServices}.
+ */
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+
+ private void advanceTime(long timeMs) {
+ mClock.fastForward(timeMs);
+ mTestLooper.dispatchAll();
+ }
+
+ private void setUpSensors() throws Exception {
+ mProxSensor = TestUtils.createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY,
+ PROX_SENSOR_MAX_RANGE);
+ Sensor screenOffBrightnessSensor = TestUtils.createSensor(
+ Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
+ when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL)))
+ .thenReturn(List.of(mProxSensor, screenOffBrightnessSensor));
+ }
+
+ private SensorEventListener getSensorEventListener(Sensor sensor) {
+ verify(mSensorManagerMock).registerListener(mSensorEventListenerCaptor.capture(),
+ eq(sensor), eq(SensorManager.SENSOR_DELAY_NORMAL), isA(Handler.class));
+ return mSensorEventListenerCaptor.getValue();
+ }
+
+ private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock,
+ DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock,
+ boolean isEnabled) {
+ DisplayInfo info = new DisplayInfo();
+ DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
+ deviceInfo.uniqueId = uniqueId;
+
+ when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
+ when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock);
+ when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
+ when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
+ when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
+ when(logicalDisplayMock.getBrightnessThrottlingDataIdLocked()).thenReturn(
+ DisplayDeviceConfig.DEFAULT_ID);
+ when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
+ when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
+ when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock);
+ when(displayDeviceConfigMock.getProximitySensor()).thenReturn(
+ new DisplayDeviceConfig.SensorData() {
+ {
+ type = Sensor.STRING_TYPE_PROXIMITY;
+ name = null;
+ }
+ });
+ when(displayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500});
+ when(displayDeviceConfigMock.isAutoBrightnessAvailable()).thenReturn(true);
+ when(displayDeviceConfigMock.getAmbientLightSensor()).thenReturn(
+ new DisplayDeviceConfig.SensorData());
+ when(displayDeviceConfigMock.getScreenOffBrightnessSensor()).thenReturn(
+ new DisplayDeviceConfig.SensorData() {
+ {
+ type = Sensor.STRING_TYPE_LIGHT;
+ name = null;
+ }
+ });
+ when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux())
+ .thenReturn(new int[0]);
+ }
+
private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
String uniqueId) {
return createDisplayPowerController(displayId, uniqueId, /* isEnabled= */ true);
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java
new file mode 100644
index 000000000000..fd9dfe869d52
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+package com.android.server.location.gnss;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.location.GnssMeasurementRequest;
+import android.location.IGnssMeasurementsListener;
+import android.location.LocationManager;
+import android.location.LocationManagerInternal;
+import android.location.util.identity.CallerIdentity;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.location.gnss.hal.FakeGnssHal;
+import com.android.server.location.gnss.hal.GnssNative;
+import com.android.server.location.injector.FakeUserInfoHelper;
+import com.android.server.location.injector.Injector;
+import com.android.server.location.injector.TestInjector;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Objects;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class GnssMeasurementsProviderTest {
+ private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID;
+ private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1000,
+ "mypackage", "attribution", "listener");
+ private static final GnssConfiguration.HalInterfaceVersion HIDL_V2_1 =
+ new GnssConfiguration.HalInterfaceVersion(
+ 2, 1);
+ private static final GnssConfiguration.HalInterfaceVersion AIDL_V3 =
+ new GnssConfiguration.HalInterfaceVersion(
+ GnssConfiguration.HalInterfaceVersion.AIDL_INTERFACE, 3);
+ private static final GnssMeasurementRequest ACTIVE_REQUEST =
+ new GnssMeasurementRequest.Builder().build();
+ private static final GnssMeasurementRequest PASSIVE_REQUEST =
+ new GnssMeasurementRequest.Builder().setIntervalMillis(
+ GnssMeasurementRequest.PASSIVE_INTERVAL).build();
+ private @Mock Context mContext;
+ private @Mock LocationManagerInternal mInternal;
+ private @Mock GnssConfiguration mMockConfiguration;
+ private @Mock GnssNative.GeofenceCallbacks mGeofenceCallbacks;
+ private @Mock IGnssMeasurementsListener mListener1;
+ private @Mock IGnssMeasurementsListener mListener2;
+ private @Mock IBinder mBinder1;
+ private @Mock IBinder mBinder2;
+
+ private GnssNative mGnssNative;
+
+ private GnssMeasurementsProvider mTestProvider;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ doReturn(mBinder1).when(mListener1).asBinder();
+ doReturn(mBinder2).when(mListener2).asBinder();
+ doReturn(true).when(mInternal).isProviderEnabledForUser(eq(LocationManager.GPS_PROVIDER),
+ anyInt());
+ LocalServices.addService(LocationManagerInternal.class, mInternal);
+ FakeGnssHal fakeGnssHal = new FakeGnssHal();
+ GnssNative.setGnssHalForTest(fakeGnssHal);
+ Injector injector = new TestInjector(mContext);
+ mGnssNative = spy(Objects.requireNonNull(
+ GnssNative.create(injector, mMockConfiguration)));
+ mGnssNative.setGeofenceCallbacks(mGeofenceCallbacks);
+ mTestProvider = new GnssMeasurementsProvider(injector, mGnssNative);
+ mGnssNative.register();
+ }
+
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(LocationManagerInternal.class);
+ }
+
+ @Test
+ public void testAddListener_active() {
+ // add the active request
+ mTestProvider.addListener(ACTIVE_REQUEST, IDENTITY, mListener1);
+ verify(mGnssNative, times(1)).startMeasurementCollection(
+ eq(ACTIVE_REQUEST.isFullTracking()),
+ eq(ACTIVE_REQUEST.isCorrelationVectorOutputsEnabled()),
+ eq(ACTIVE_REQUEST.getIntervalMillis()));
+
+ // remove the active request
+ mTestProvider.removeListener(mListener1);
+ verify(mGnssNative, times(1)).stopMeasurementCollection();
+ }
+
+ @Test
+ public void testAddListener_passive() {
+ // add the passive request
+ mTestProvider.addListener(PASSIVE_REQUEST, IDENTITY, mListener1);
+ verify(mGnssNative, never()).startMeasurementCollection(anyBoolean(), anyBoolean(),
+ anyInt());
+
+ // remove the passive request
+ mTestProvider.removeListener(mListener1);
+ verify(mGnssNative, times(1)).stopMeasurementCollection();
+ }
+
+ @Test
+ public void testReregister_aidlV3Plus() {
+ doReturn(AIDL_V3).when(mMockConfiguration).getHalInterfaceVersion();
+
+ // add the passive request
+ mTestProvider.addListener(PASSIVE_REQUEST, IDENTITY, mListener1);
+ verify(mGnssNative, never()).startMeasurementCollection(anyBoolean(), anyBoolean(),
+ anyInt());
+
+ // add the active request, reregister with the active request
+ mTestProvider.addListener(ACTIVE_REQUEST, IDENTITY, mListener2);
+ verify(mGnssNative, never()).stopMeasurementCollection();
+ verify(mGnssNative, times(1)).startMeasurementCollection(
+ eq(ACTIVE_REQUEST.isFullTracking()),
+ eq(ACTIVE_REQUEST.isCorrelationVectorOutputsEnabled()),
+ eq(ACTIVE_REQUEST.getIntervalMillis()));
+
+ // remove the active request, reregister with the passive request
+ mTestProvider.removeListener(mListener2);
+ verify(mGnssNative, times(1)).stopMeasurementCollection();
+
+ // remove the passive request
+ mTestProvider.removeListener(mListener1);
+ verify(mGnssNative, times(2)).stopMeasurementCollection();
+ }
+
+ @Test
+ public void testReregister_preAidlV3() {
+ doReturn(HIDL_V2_1).when(mMockConfiguration).getHalInterfaceVersion();
+
+ // add the passive request
+ mTestProvider.addListener(PASSIVE_REQUEST, IDENTITY, mListener1);
+ verify(mGnssNative, never()).startMeasurementCollection(anyBoolean(), anyBoolean(),
+ anyInt());
+
+ // add the active request, reregister with the active request
+ mTestProvider.addListener(ACTIVE_REQUEST, IDENTITY, mListener2);
+ verify(mGnssNative, times(1)).stopMeasurementCollection();
+ verify(mGnssNative, times(1)).startMeasurementCollection(
+ eq(ACTIVE_REQUEST.isFullTracking()),
+ eq(ACTIVE_REQUEST.isCorrelationVectorOutputsEnabled()),
+ eq(ACTIVE_REQUEST.getIntervalMillis()));
+
+ // remove the active request, reregister with the passive request
+ mTestProvider.removeListener(mListener2);
+ verify(mGnssNative, times(2)).stopMeasurementCollection();
+
+ // remove the passive request
+ mTestProvider.removeListener(mListener1);
+ verify(mGnssNative, times(3)).stopMeasurementCollection();
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index c73237efa93e..0ae579bab413 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -376,46 +376,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
}
@Test
- public void testGetAnimationTargets_windowsAreBeingReplaced() {
- // [DisplayContent] -+- [Task1] - [ActivityRecord1] (opening, visible)
- // +- [AppWindow1] (being-replaced)
- // +- [Task2] - [ActivityRecord2] (closing, invisible)
- // +- [AppWindow2] (being-replaced)
- final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
- final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
- TYPE_BASE_APPLICATION);
- attrs.setTitle("AppWindow1");
- final TestWindowState appWindow1 = createWindowState(attrs, activity1);
- appWindow1.mWillReplaceWindow = true;
- activity1.addWindow(appWindow1);
-
- final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
- activity2.setVisible(false);
- activity2.setVisibleRequested(false);
- attrs.setTitle("AppWindow2");
- final TestWindowState appWindow2 = createWindowState(attrs, activity2);
- appWindow2.mWillReplaceWindow = true;
- activity2.addWindow(appWindow2);
-
- final ArraySet<ActivityRecord> opening = new ArraySet<>();
- opening.add(activity1);
- final ArraySet<ActivityRecord> closing = new ArraySet<>();
- closing.add(activity2);
-
- // Animate opening apps even if it's already visible in case its windows are being replaced.
- // Don't animate closing apps if it's already invisible even though its windows are being
- // replaced.
- assertEquals(
- new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}),
- AppTransitionController.getAnimationTargets(
- opening, closing, true /* visible */));
- assertEquals(
- new ArraySet<>(new WindowContainer[]{}),
- AppTransitionController.getAnimationTargets(
- opening, closing, false /* visible */));
- }
-
- @Test
public void testGetAnimationTargets_openingClosingInDifferentTask() {
// [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible)
// | +- [ActivityRecord2] (invisible)
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 7d6cf4a63c43..677ec46007ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -26,7 +26,10 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLI
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_OWN_FOCUS;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -49,11 +52,13 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -67,12 +72,16 @@ import android.hardware.display.VirtualDisplay;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.InputConfig;
+import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.util.MergedConfiguration;
+import android.view.IWindow;
import android.view.IWindowSessionCallback;
+import android.view.InputChannel;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.Surface;
@@ -690,6 +699,102 @@ public class WindowManagerServiceTests extends WindowTestsBase {
assertEquals(validRect, resultingArgs.mSourceCrop);
}
+ @Test
+ public void testGrantInputChannel_sanitizeSpyWindowForApplications() {
+ final Session session = mock(Session.class);
+ final int callingUid = Process.FIRST_APPLICATION_UID;
+ final int callingPid = 1234;
+ final SurfaceControl surfaceControl = mock(SurfaceControl.class);
+ final IWindow window = mock(IWindow.class);
+ final IBinder windowToken = mock(IBinder.class);
+ when(window.asBinder()).thenReturn(windowToken);
+ final IBinder focusGrantToken = mock(IBinder.class);
+
+ final InputChannel inputChannel = new InputChannel();
+ assertThrows(IllegalArgumentException.class, () ->
+ mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY,
+ surfaceControl, window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE,
+ PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY, TYPE_APPLICATION,
+ null /* windowToken */, focusGrantToken, "TestInputChannel",
+ inputChannel));
+ }
+
+ @Test
+ public void testGrantInputChannel_allowSpyWindowForInputMonitorPermission() {
+ final Session session = mock(Session.class);
+ final int callingUid = Process.SYSTEM_UID;
+ final int callingPid = 1234;
+ final SurfaceControl surfaceControl = mock(SurfaceControl.class);
+ final IWindow window = mock(IWindow.class);
+ final IBinder windowToken = mock(IBinder.class);
+ when(window.asBinder()).thenReturn(windowToken);
+ final IBinder focusGrantToken = mock(IBinder.class);
+
+ final InputChannel inputChannel = new InputChannel();
+ mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl,
+ window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY,
+ INPUT_FEATURE_SPY, TYPE_APPLICATION, null /* windowToken */, focusGrantToken,
+ "TestInputChannel", inputChannel);
+
+ verify(mTransaction).setInputWindowInfo(
+ eq(surfaceControl),
+ argThat(h -> (h.inputConfig & InputConfig.SPY) == InputConfig.SPY));
+ }
+
+ @Test
+ public void testUpdateInputChannel_sanitizeSpyWindowForApplications() {
+ final Session session = mock(Session.class);
+ final int callingUid = Process.FIRST_APPLICATION_UID;
+ final int callingPid = 1234;
+ final SurfaceControl surfaceControl = mock(SurfaceControl.class);
+ final IWindow window = mock(IWindow.class);
+ final IBinder windowToken = mock(IBinder.class);
+ when(window.asBinder()).thenReturn(windowToken);
+ final IBinder focusGrantToken = mock(IBinder.class);
+
+ final InputChannel inputChannel = new InputChannel();
+ mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl,
+ window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY,
+ 0 /* inputFeatures */, TYPE_APPLICATION, null /* windowToken */, focusGrantToken,
+ "TestInputChannel", inputChannel);
+ verify(mTransaction).setInputWindowInfo(
+ eq(surfaceControl),
+ argThat(h -> (h.inputConfig & InputConfig.SPY) == 0));
+
+ assertThrows(IllegalArgumentException.class, () ->
+ mWm.updateInputChannel(inputChannel.getToken(), DEFAULT_DISPLAY, surfaceControl,
+ FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY,
+ null /* region */));
+ }
+
+ @Test
+ public void testUpdateInputChannel_allowSpyWindowForInputMonitorPermission() {
+ final Session session = mock(Session.class);
+ final int callingUid = Process.SYSTEM_UID;
+ final int callingPid = 1234;
+ final SurfaceControl surfaceControl = mock(SurfaceControl.class);
+ final IWindow window = mock(IWindow.class);
+ final IBinder windowToken = mock(IBinder.class);
+ when(window.asBinder()).thenReturn(windowToken);
+ final IBinder focusGrantToken = mock(IBinder.class);
+
+ final InputChannel inputChannel = new InputChannel();
+ mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl,
+ window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY,
+ 0 /* inputFeatures */, TYPE_APPLICATION, null /* windowToken */, focusGrantToken,
+ "TestInputChannel", inputChannel);
+ verify(mTransaction).setInputWindowInfo(
+ eq(surfaceControl),
+ argThat(h -> (h.inputConfig & InputConfig.SPY) == 0));
+
+ mWm.updateInputChannel(inputChannel.getToken(), DEFAULT_DISPLAY, surfaceControl,
+ FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY,
+ null /* region */);
+ verify(mTransaction).setInputWindowInfo(
+ eq(surfaceControl),
+ argThat(h -> (h.inputConfig & InputConfig.SPY) == InputConfig.SPY));
+ }
+
private void setupActivityWithLaunchCookie(IBinder launchCookie, WindowContainerToken wct) {
final WindowContainer.RemoteToken remoteToken = mock(WindowContainer.RemoteToken.class);
when(remoteToken.toWindowContainerToken()).thenReturn(wct);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
index 06fc41626e50..dbc824c384a2 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
@@ -68,6 +68,7 @@ import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SharedMemory;
+import android.service.voice.DetectorFailure;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordDetectionService;
import android.service.voice.HotwordDetectionServiceFailure;
@@ -623,11 +624,9 @@ abstract class DetectorSession {
mRemoteDetectionService = remoteDetectionService;
}
- void reportErrorLocked(int errorCode, @NonNull String errorMessage) {
+ void reportErrorLocked(@NonNull DetectorFailure detectorFailure) {
try {
- // TODO: Use instanceof(this) to get different detector to set the right error source.
- mCallback.onDetectionFailure(
- new HotwordDetectionServiceFailure(errorCode, errorMessage));
+ mCallback.onDetectionFailure(detectorFailure);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to report onError status: " + e);
if (getDetectorType() != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 025e1dc78c86..4fd5979b3d9f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -51,11 +51,14 @@ import android.os.ServiceManager;
import android.os.SharedMemory;
import android.provider.DeviceConfig;
import android.service.voice.HotwordDetectionService;
+import android.service.voice.HotwordDetectionServiceFailure;
import android.service.voice.HotwordDetector;
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
import android.service.voice.ISandboxedDetectionService;
import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
+import android.service.voice.UnknownFailure;
import android.service.voice.VisualQueryDetectionService;
+import android.service.voice.VisualQueryDetectionServiceFailure;
import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
import android.speech.IRecognitionServiceManager;
import android.util.Slog;
@@ -109,6 +112,16 @@ final class HotwordDetectionConnection {
private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
private static final int MAX_ISOLATED_PROCESS_NUMBER = 10;
+ /**
+ * Indicates the {@link HotwordDetectionService} is created.
+ */
+ private static final int DETECTION_SERVICE_TYPE_HOTWORD = 1;
+
+ /**
+ * Indicates the {@link VisualQueryDetectionService} is created.
+ */
+ private static final int DETECTION_SERVICE_TYPE_VISUAL_QUERY = 2;
+
// TODO: This may need to be a Handler(looper)
private final ScheduledExecutorService mScheduledExecutorService =
Executors.newSingleThreadScheduledExecutor();
@@ -186,11 +199,11 @@ final class HotwordDetectionConnection {
mHotwordDetectionServiceConnectionFactory =
new ServiceConnectionFactory(hotwordDetectionServiceIntent,
- bindInstantServiceAllowed);
+ bindInstantServiceAllowed, DETECTION_SERVICE_TYPE_HOTWORD);
mVisualQueryDetectionServiceConnectionFactory =
new ServiceConnectionFactory(visualQueryDetectionServiceIntent,
- bindInstantServiceAllowed);
+ bindInstantServiceAllowed, DETECTION_SERVICE_TYPE_VISUAL_QUERY);
mLastRestartInstant = Instant.now();
@@ -604,17 +617,20 @@ final class HotwordDetectionConnection {
private class ServiceConnectionFactory {
private final Intent mIntent;
private final int mBindingFlags;
+ private final int mDetectionServiceType;
- ServiceConnectionFactory(@NonNull Intent intent, boolean bindInstantServiceAllowed) {
+ ServiceConnectionFactory(@NonNull Intent intent, boolean bindInstantServiceAllowed,
+ int detectionServiceType) {
mIntent = intent;
mBindingFlags = bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0;
+ mDetectionServiceType = detectionServiceType;
}
ServiceConnection createLocked() {
ServiceConnection connection =
new ServiceConnection(mContext, mIntent, mBindingFlags, mUser,
ISandboxedDetectionService.Stub::asInterface,
- mRestartCount % MAX_ISOLATED_PROCESS_NUMBER);
+ mRestartCount % MAX_ISOLATED_PROCESS_NUMBER, mDetectionServiceType);
connection.connect();
updateAudioFlinger(connection, mAudioFlinger);
@@ -635,15 +651,17 @@ final class HotwordDetectionConnection {
private boolean mRespectServiceConnectionStatusChanged = true;
private boolean mIsBound = false;
private boolean mIsLoggedFirstConnect = false;
+ private final int mDetectionServiceType;
ServiceConnection(@NonNull Context context,
@NonNull Intent serviceIntent, int bindingFlags, int userId,
@Nullable Function<IBinder, ISandboxedDetectionService> binderAsInterface,
- int instanceNumber) {
+ int instanceNumber, int detectionServiceType) {
super(context, serviceIntent, bindingFlags, userId, binderAsInterface);
this.mIntent = serviceIntent;
this.mBindingFlags = bindingFlags;
this.mInstanceNumber = instanceNumber;
+ this.mDetectionServiceType = detectionServiceType;
}
@Override // from ServiceConnector.Impl
@@ -660,14 +678,14 @@ final class HotwordDetectionConnection {
mIsBound = connected;
if (!connected) {
- if (mDetectorType != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
+ if (mDetectionServiceType != DETECTION_SERVICE_TYPE_VISUAL_QUERY) {
HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
HOTWORD_DETECTOR_EVENTS__EVENT__ON_DISCONNECTED,
mVoiceInteractionServiceUid);
}
} else if (!mIsLoggedFirstConnect) {
mIsLoggedFirstConnect = true;
- if (mDetectorType != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
+ if (mDetectionServiceType != DETECTION_SERVICE_TYPE_VISUAL_QUERY) {
HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
HOTWORD_DETECTOR_EVENTS__EVENT__ON_CONNECTED,
mVoiceInteractionServiceUid);
@@ -684,7 +702,7 @@ final class HotwordDetectionConnection {
@Override
public void binderDied() {
super.binderDied();
- Slog.w(TAG, "binderDied");
+ Slog.w(TAG, "binderDied mDetectionServiceType = " + mDetectionServiceType);
synchronized (mLock) {
if (!mRespectServiceConnectionStatusChanged) {
Slog.v(TAG, "Ignored #binderDied event");
@@ -693,13 +711,10 @@ final class HotwordDetectionConnection {
}
//TODO(b265535257): report error to either service only.
synchronized (HotwordDetectionConnection.this.mLock) {
- runForEachDetectorSessionLocked((session) -> {
- session.reportErrorLocked(DetectorSession.HOTWORD_DETECTION_SERVICE_DIED,
- "Detection service is dead.");
- });
+ runForEachDetectorSessionLocked(this::reportBinderDiedLocked);
}
// Can improve to log exit reason if needed
- if (mDetectorType != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
+ if (mDetectionServiceType != DETECTION_SERVICE_TYPE_VISUAL_QUERY) {
HotwordMetricsLogger.writeKeyphraseTriggerEvent(
mDetectorType,
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__SERVICE_CRASH,
@@ -711,7 +726,7 @@ final class HotwordDetectionConnection {
protected boolean bindService(
@NonNull android.content.ServiceConnection serviceConnection) {
try {
- if (mDetectorType != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
+ if (mDetectionServiceType != DETECTION_SERVICE_TYPE_VISUAL_QUERY) {
HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE,
mVoiceInteractionServiceUid);
@@ -723,7 +738,12 @@ final class HotwordDetectionConnection {
mExecutor,
serviceConnection);
if (!bindResult) {
- if (mDetectorType != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
+ Slog.w(TAG,
+ "bindService failure mDetectionServiceType = " + mDetectionServiceType);
+ synchronized (HotwordDetectionConnection.this.mLock) {
+ runForEachDetectorSessionLocked(this::reportBindServiceFailureLocked);
+ }
+ if (mDetectionServiceType != DETECTION_SERVICE_TYPE_VISUAL_QUERY) {
HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE_FAIL,
mVoiceInteractionServiceUid);
@@ -731,7 +751,7 @@ final class HotwordDetectionConnection {
}
return bindResult;
} catch (IllegalArgumentException e) {
- if (mDetectorType != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
+ if (mDetectionServiceType != DETECTION_SERVICE_TYPE_VISUAL_QUERY) {
HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE_FAIL,
mVoiceInteractionServiceUid);
@@ -752,6 +772,42 @@ final class HotwordDetectionConnection {
mRespectServiceConnectionStatusChanged = false;
}
}
+
+ private void reportBinderDiedLocked(DetectorSession detectorSession) {
+ if (mDetectionServiceType == DETECTION_SERVICE_TYPE_HOTWORD && (
+ detectorSession instanceof DspTrustedHotwordDetectorSession
+ || detectorSession instanceof SoftwareTrustedHotwordDetectorSession)) {
+ detectorSession.reportErrorLocked(new HotwordDetectionServiceFailure(
+ HotwordDetectionServiceFailure.ERROR_CODE_BINDING_DIED,
+ "Detection service is dead."));
+ } else if (mDetectionServiceType == DETECTION_SERVICE_TYPE_VISUAL_QUERY
+ && detectorSession instanceof VisualQueryDetectorSession) {
+ detectorSession.reportErrorLocked(new VisualQueryDetectionServiceFailure(
+ VisualQueryDetectionServiceFailure.ERROR_CODE_BINDING_DIED,
+ "Detection service is dead."));
+ } else {
+ detectorSession.reportErrorLocked(new UnknownFailure(
+ "Detection service is dead with unknown detection service type."));
+ }
+ }
+
+ private void reportBindServiceFailureLocked(DetectorSession detectorSession) {
+ if (mDetectionServiceType == DETECTION_SERVICE_TYPE_HOTWORD && (
+ detectorSession instanceof DspTrustedHotwordDetectorSession
+ || detectorSession instanceof SoftwareTrustedHotwordDetectorSession)) {
+ detectorSession.reportErrorLocked(new HotwordDetectionServiceFailure(
+ HotwordDetectionServiceFailure.ERROR_CODE_BIND_FAILURE,
+ "Bind detection service failure."));
+ } else if (mDetectionServiceType == DETECTION_SERVICE_TYPE_VISUAL_QUERY
+ && detectorSession instanceof VisualQueryDetectorSession) {
+ detectorSession.reportErrorLocked(new VisualQueryDetectionServiceFailure(
+ VisualQueryDetectionServiceFailure.ERROR_CODE_BIND_FAILURE,
+ "Bind detection service failure."));
+ } else {
+ detectorSession.reportErrorLocked(new UnknownFailure(
+ "Bind detection service failure with unknown detection service type."));
+ }
+ }
}
@SuppressWarnings("GuardedBy")
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 212dc41b3de3..7aa1334fd1c3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -8654,6 +8654,16 @@ public class CarrierConfigManager {
public static final String KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY =
KEY_PREFIX + "epdg_address_priority_int_array";
+ /**
+ * A priority list of PLMN to be used in EPDG_ADDRESS_PLMN. Possible values are {@link
+ * #EPDG_PLMN_RPLMN}, {@link #EPDG_PLMN_HPLMN}, {@link #EPDG_PLMN_EHPLMN_ALL}, {@link
+ * #EPDG_PLMN_EHPLMN_FIRST}
+ *
+ * @hide
+ */
+ public static final String KEY_EPDG_PLMN_PRIORITY_INT_ARRAY =
+ KEY_PREFIX + "epdg_plmn_priority_int_array";
+
/** Epdg static IP address or FQDN */
public static final String KEY_EPDG_STATIC_ADDRESS_STRING =
KEY_PREFIX + "epdg_static_address_string";
@@ -8854,6 +8864,36 @@ public class CarrierConfigManager {
public static final int EPDG_ADDRESS_VISITED_COUNTRY = 4;
/** @hide */
+ @IntDef({
+ EPDG_PLMN_RPLMN,
+ EPDG_PLMN_HPLMN,
+ EPDG_PLMN_EHPLMN_ALL,
+ EPDG_PLMN_EHPLMN_FIRST
+ })
+ public @interface EpdgAddressPlmnType {}
+
+ /**
+ * Use the Registered PLMN
+ * @hide
+ */
+ public static final int EPDG_PLMN_RPLMN = 0;
+ /**
+ * Use the PLMN derived from IMSI
+ * @hide
+ */
+ public static final int EPDG_PLMN_HPLMN = 1;
+ /**
+ * Use all EHPLMN from SIM EF files
+ * @hide
+ */
+ public static final int EPDG_PLMN_EHPLMN_ALL = 2;
+ /**
+ * Use the first EHPLMN from SIM EF files
+ * @hide
+ */
+ public static final int EPDG_PLMN_EHPLMN_FIRST = 3;
+
+ /** @hide */
@IntDef({ID_TYPE_FQDN, ID_TYPE_RFC822_ADDR, ID_TYPE_KEY_ID})
public @interface IkeIdType {}
@@ -8988,6 +9028,12 @@ public class CarrierConfigManager {
defaults.putIntArray(
KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
new int[] {EPDG_ADDRESS_PLMN, EPDG_ADDRESS_STATIC});
+ defaults.putIntArray(
+ KEY_EPDG_PLMN_PRIORITY_INT_ARRAY,
+ new int[]{
+ EPDG_PLMN_RPLMN,
+ EPDG_PLMN_HPLMN,
+ EPDG_PLMN_EHPLMN_ALL});
defaults.putStringArray(KEY_MCC_MNCS_STRING_ARRAY, new String[0]);
defaults.putInt(KEY_IKE_LOCAL_ID_TYPE_INT, ID_TYPE_RFC822_ADDR);
defaults.putInt(KEY_IKE_REMOTE_ID_TYPE_INT, ID_TYPE_FQDN);
diff --git a/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl b/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl
index 24420833bdb6..a81444d51374 100644
--- a/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl
+++ b/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl
@@ -24,15 +24,22 @@ import android.telephony.satellite.PointingInfo;
*/
oneway interface ISatelliteTransmissionUpdateCallback {
/**
- * Called when satellite datagram transfer state changed.
+ * Called when satellite datagram send state changed.
*
- * @param state The new datagram transfer state.
+ * @param state The new send datagram transfer state.
* @param sendPendingCount The number of datagrams that are currently being sent.
- * @param receivePendingCount The number of datagrams that are currently being received.
* @param errorCode If datagram transfer failed, the reason for failure.
*/
- void onDatagramTransferStateChanged(in int state, in int sendPendingCount,
- in int receivePendingCount, in int errorCode);
+ void onSendDatagramStateChanged(in int state, in int sendPendingCount, in int errorCode);
+
+ /**
+ * Called when satellite datagram receive state changed.
+ *
+ * @param state The new receive datagram transfer state.
+ * @param receivePendingCount The number of datagrams that are currently pending to be received.
+ * @param errorCode If datagram transfer failed, the reason for failure.
+ */
+ void onReceiveDatagramStateChanged(in int state, in int receivePendingCount, in int errorCode);
/**
* Called when the satellite position changed.
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index d0abfbf80e76..e32566dc470f 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -647,6 +647,7 @@ public class SatelliteManager {
})
@Retention(RetentionPolicy.SOURCE)
public @interface SatelliteDatagramTransferState {}
+ // TODO: Split into two enums for sending and receiving states
/**
* Satellite modem is in idle state.
@@ -750,19 +751,27 @@ public class SatelliteManager {
};
ISatelliteTransmissionUpdateCallback internalCallback =
new ISatelliteTransmissionUpdateCallback.Stub() {
+
@Override
- public void onDatagramTransferStateChanged(int state,
- int sendPendingCount, int receivePendingCount, int errorCode) {
+ public void onSatellitePositionChanged(PointingInfo pointingInfo) {
executor.execute(() -> Binder.withCleanCallingIdentity(
- () -> callback.onDatagramTransferStateChanged(
- state, sendPendingCount, receivePendingCount,
- errorCode)));
+ () -> callback.onSatellitePositionChanged(pointingInfo)));
}
@Override
- public void onSatellitePositionChanged(PointingInfo pointingInfo) {
+ public void onSendDatagramStateChanged(int state, int sendPendingCount,
+ int errorCode) {
executor.execute(() -> Binder.withCleanCallingIdentity(
- () -> callback.onSatellitePositionChanged(pointingInfo)));
+ () -> callback.onSendDatagramStateChanged(
+ state, sendPendingCount, errorCode)));
+ }
+
+ @Override
+ public void onReceiveDatagramStateChanged(int state,
+ int receivePendingCount, int errorCode) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> callback.onReceiveDatagramStateChanged(
+ state, receivePendingCount, errorCode)));
}
};
sSatelliteTransmissionUpdateCallbackMap.put(callback, internalCallback);
diff --git a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
index 0efbd1fbdfef..d4fe57a0be2e 100644
--- a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
@@ -33,14 +33,24 @@ public interface SatelliteTransmissionUpdateCallback {
void onSatellitePositionChanged(@NonNull PointingInfo pointingInfo);
/**
- * Called when satellite datagram transfer state changed.
+ * Called when satellite datagram send state changed.
*
- * @param state The new datagram transfer state.
+ * @param state The new send datagram transfer state.
* @param sendPendingCount The number of datagrams that are currently being sent.
- * @param receivePendingCount The number of datagrams that are currently being received.
* @param errorCode If datagram transfer failed, the reason for failure.
*/
- void onDatagramTransferStateChanged(@SatelliteManager.SatelliteDatagramTransferState int state,
- int sendPendingCount, int receivePendingCount,
+ void onSendDatagramStateChanged(
+ @SatelliteManager.SatelliteDatagramTransferState int state, int sendPendingCount,
+ @SatelliteManager.SatelliteError int errorCode);
+
+ /**
+ * Called when satellite datagram receive state changed.
+ *
+ * @param state The new receive datagram transfer state.
+ * @param receivePendingCount The number of datagrams that are currently pending to be received.
+ * @param errorCode If datagram transfer failed, the reason for failure.
+ */
+ void onReceiveDatagramStateChanged(
+ @SatelliteManager.SatelliteDatagramTransferState int state, int receivePendingCount,
@SatelliteManager.SatelliteError int errorCode);
}
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index 83893ba46885..a4c48fd5f342 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -13,6 +13,9 @@ android_test {
"src/**/*.java",
"src/**/*.kt",
],
+ kotlincflags: [
+ "-Werror",
+ ],
platform_apis: true,
certificate: "platform",
static_libs: [
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
index 1d65cc35c3bc..0246426c1d33 100644
--- a/tests/Input/src/com/android/test/input/AnrTest.kt
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -73,7 +73,7 @@ class AnrTest {
val contentResolver = instrumentation.targetContext.contentResolver
hideErrorDialogs = Settings.Global.getInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
- PACKAGE_NAME = UnresponsiveGestureMonitorActivity::class.java.getPackage().getName()
+ PACKAGE_NAME = UnresponsiveGestureMonitorActivity::class.java.getPackage()!!.getName()
}
@After
diff --git a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
index d83a4570fedc..3a24406e2b73 100644
--- a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
+++ b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
@@ -45,7 +45,8 @@ class UnresponsiveGestureMonitorActivity : Activity() {
private lateinit var mInputMonitor: InputMonitor
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- mInputMonitor = InputManager.getInstance().monitorGestureInput(MONITOR_NAME, displayId)
+ val inputManager = getSystemService(InputManager::class.java)
+ mInputMonitor = inputManager.monitorGestureInput(MONITOR_NAME, displayId)
mInputEventReceiver = UnresponsiveReceiver(
mInputMonitor.getInputChannel(), Looper.myLooper())
}
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
index 423a6843891e..b4f6a1c12d8f 100644
--- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
+++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
@@ -36,7 +36,6 @@ class AndroidFrameworkIssueRegistry : IssueRegistry() {
CallingSettingsNonUserGetterMethodsDetector.ISSUE_NON_USER_GETTER_CALLED,
SaferParcelChecker.ISSUE_UNSAFE_API_USAGE,
PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS,
- RegisterReceiverFlagDetector.ISSUE_RECEIVER_EXPORTED_FLAG,
PermissionMethodDetector.ISSUE_PERMISSION_METHOD_USAGE,
PermissionMethodDetector.ISSUE_CAN_BE_PERMISSION_METHOD,
)
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
deleted file mode 100644
index c3e0428316c3..000000000000
--- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
+++ /dev/null
@@ -1,927 +0,0 @@
-/*
- * Copyright (C) 2021 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.google.android.lint
-
-import com.android.tools.lint.checks.DataFlowAnalyzer
-import com.android.tools.lint.detector.api.Category
-import com.android.tools.lint.detector.api.ConstantEvaluator
-import com.android.tools.lint.detector.api.Detector
-import com.android.tools.lint.detector.api.Implementation
-import com.android.tools.lint.detector.api.Issue
-import com.android.tools.lint.detector.api.JavaContext
-import com.android.tools.lint.detector.api.Scope
-import com.android.tools.lint.detector.api.Severity
-import com.android.tools.lint.detector.api.SourceCodeScanner
-import com.android.tools.lint.detector.api.UastLintUtils.Companion.findLastAssignment
-import com.android.tools.lint.detector.api.getMethodName
-import com.intellij.psi.PsiMethod
-import com.intellij.psi.PsiVariable
-import org.jetbrains.kotlin.psi.psiUtil.parameterIndex
-import org.jetbrains.uast.UCallExpression
-import org.jetbrains.uast.UElement
-import org.jetbrains.uast.UExpression
-import org.jetbrains.uast.UParenthesizedExpression
-import org.jetbrains.uast.UQualifiedReferenceExpression
-import org.jetbrains.uast.getContainingUMethod
-import org.jetbrains.uast.isNullLiteral
-import org.jetbrains.uast.skipParenthesizedExprDown
-import org.jetbrains.uast.tryResolve
-
-/**
- * Detector that identifies `registerReceiver()` calls which are missing the `RECEIVER_EXPORTED` or
- * `RECEIVER_NOT_EXPORTED` flags on T+.
- *
- * TODO: Add API level conditions to better support non-platform code.
- * 1. Check if registerReceiver() call is reachable on T+.
- * 2. Check if targetSdkVersion is T+.
- *
- * eg: isWithinVersionCheckConditional(context, node, 31, false)
- * eg: isPrecededByVersionCheckExit(context, node, 31) ?
- */
-@Suppress("UnstableApiUsage")
-class RegisterReceiverFlagDetector : Detector(), SourceCodeScanner {
-
- override fun getApplicableMethodNames(): List<String> = listOf(
- "registerReceiver",
- "registerReceiverAsUser",
- "registerReceiverForAllUsers"
- )
-
- private fun checkIsProtectedReceiverAndReturnUnprotectedActions(
- filterArg: UExpression,
- node: UCallExpression,
- evaluator: ConstantEvaluator
- ): Pair<Boolean, List<String>> { // isProtected, unprotectedActions
- val actions = mutableSetOf<String>()
- val construction = findIntentFilterConstruction(filterArg, node)
-
- if (construction == null) return Pair(false, listOf<String>())
- val constructorActionArg = construction.getArgumentForParameter(0)
- (constructorActionArg?.let(evaluator::evaluate) as? String)?.let(actions::add)
-
- val actionCollectorVisitor =
- ActionCollectorVisitor(setOf(construction), node, evaluator)
-
- val parent = node.getContainingUMethod()
- parent?.accept(actionCollectorVisitor)
- actions.addAll(actionCollectorVisitor.actions)
-
- // If we failed to evaluate any actions, there will be a null action in the set.
- val isProtected =
- actions.all(PROTECTED_BROADCASTS::contains) &&
- !actionCollectorVisitor.intentFilterEscapesScope
- val unprotectedActionsList = actions.filterNot(PROTECTED_BROADCASTS::contains)
- return Pair(isProtected, unprotectedActionsList)
- }
-
- override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
- if (!context.evaluator.isMemberInSubClassOf(method, "android.content.Context")) return
-
- // The parameter positions vary across the various registerReceiver*() methods, so rather
- // than hardcode them we simply look them up based on the parameter name and type.
- val receiverArg =
- findArgument(node, method, "android.content.BroadcastReceiver", "receiver")
- val filterArg = findArgument(node, method, "android.content.IntentFilter", "filter")
- val flagsArg = findArgument(node, method, "int", "flags")
-
- if (receiverArg == null || receiverArg.isNullLiteral() || filterArg == null) {
- return
- }
-
- val evaluator = ConstantEvaluator().allowFieldInitializers()
-
- val (isProtected, unprotectedActionsList) =
- checkIsProtectedReceiverAndReturnUnprotectedActions(filterArg, node, evaluator)
-
- val flags = evaluator.evaluate(flagsArg) as? Int
-
- if (!isProtected) {
- val actionsList = unprotectedActionsList.joinToString(", ", "", "", -1, "")
- val message = "$receiverArg is missing 'RECEIVED_EXPORTED` or 'RECEIVE_NOT_EXPORTED' " +
- "flag for unprotected broadcast(s) registered for $actionsList."
- if (flagsArg == null) {
- context.report(
- ISSUE_RECEIVER_EXPORTED_FLAG, node, context.getLocation(node), message)
- } else if (flags != null && (flags and RECEIVER_EXPORTED_FLAG_PRESENT_MASK) == 0) {
- context.report(
- ISSUE_RECEIVER_EXPORTED_FLAG, node, context.getLocation(flagsArg), message)
- }
- }
-
- if (DEBUG) {
- println(node.asRenderString())
- println("Unprotected Actions: $unprotectedActionsList")
- println("Protected: $isProtected")
- println("Flags: $flags")
- }
- }
-
- /** Finds the first argument of a method that matches the given parameter type and name. */
- private fun findArgument(
- node: UCallExpression,
- method: PsiMethod,
- type: String,
- name: String
- ): UExpression? {
- val psiParameter = method.parameterList.parameters.firstOrNull {
- it.type.canonicalText == type && it.name == name
- } ?: return null
- val argument = node.getArgumentForParameter(psiParameter.parameterIndex())
- return argument?.skipParenthesizedExprDown()
- }
-
- /**
- * For the supplied expression (eg. intent filter argument), attempts to find its construction.
- * This will be an `IntentFilter()` constructor, an `IntentFilter.create()` call, or `null`.
- */
- private fun findIntentFilterConstruction(
- expression: UExpression,
- node: UCallExpression
- ): UCallExpression? {
- val resolved = expression.tryResolve()
-
- if (resolved is PsiVariable) {
- val assignment = findLastAssignment(resolved, node) ?: return null
- return findIntentFilterConstruction(assignment, node)
- }
-
- if (expression is UParenthesizedExpression) {
- return findIntentFilterConstruction(expression.expression, node)
- }
-
- if (expression is UQualifiedReferenceExpression) {
- val call = expression.selector as? UCallExpression ?: return null
- return if (isReturningContext(call)) {
- // eg. filter.apply { addAction("abc") } --> use filter variable.
- findIntentFilterConstruction(expression.receiver, node)
- } else {
- // eg. IntentFilter.create("abc") --> use create("abc") UCallExpression.
- findIntentFilterConstruction(call, node)
- }
- }
-
- val method = resolved as? PsiMethod ?: return null
- return if (isIntentFilterFactoryMethod(method)) {
- expression as? UCallExpression
- } else {
- null
- }
- }
-
- private fun isIntentFilterFactoryMethod(method: PsiMethod) =
- (method.containingClass?.qualifiedName == "android.content.IntentFilter" &&
- (method.returnType?.canonicalText == "android.content.IntentFilter" ||
- method.isConstructor))
-
- /**
- * Returns true if the given call represents a Kotlin scope function where the return value is
- * the context object; see https://kotlinlang.org/docs/scope-functions.html#function-selection.
- */
- private fun isReturningContext(node: UCallExpression): Boolean {
- val name = getMethodName(node)
- if (name == "apply" || name == "also") {
- return isScopingFunction(node)
- }
- return false
- }
-
- /**
- * Returns true if the given node appears to be one of the scope functions. Only checks parent
- * class; caller should intend that it's actually one of let, with, apply, etc.
- */
- private fun isScopingFunction(node: UCallExpression): Boolean {
- val called = node.resolve() ?: return true
- // See libraries/stdlib/jvm/build/stdlib-declarations.json
- return called.containingClass?.qualifiedName == "kotlin.StandardKt__StandardKt"
- }
-
- inner class ActionCollectorVisitor(
- start: Collection<UElement>,
- val functionCall: UCallExpression,
- val evaluator: ConstantEvaluator,
- ) : DataFlowAnalyzer(start) {
- private var finished = false
- var intentFilterEscapesScope = false; private set
- val actions = mutableSetOf<String>()
-
- override fun argument(call: UCallExpression, reference: UElement) {
- // TODO: Remove this temporary fix for DataFlowAnalyzer bug (ag/15787550):
- if (reference !in call.valueArguments) return
- val methodNames = super@RegisterReceiverFlagDetector.getApplicableMethodNames()
- when {
- finished -> return
- // We've reached the registerReceiver*() call in question.
- call == functionCall -> finished = true
- // The filter 'intentFilterEscapesScope' to a method which could modify it.
- methodNames != null && getMethodName(call)!! !in methodNames ->
- intentFilterEscapesScope = true
- }
- }
-
- // Fixed in b/199163915: DataFlowAnalyzer doesn't call this for Kotlin properties.
- override fun field(field: UElement) {
- if (!finished) intentFilterEscapesScope = true
- }
-
- override fun receiver(call: UCallExpression) {
- if (!finished && getMethodName(call) == "addAction") {
- val actionArg = call.getArgumentForParameter(0)
- if (actionArg != null) {
- val action = evaluator.evaluate(actionArg) as? String
- if (action != null) actions.add(action)
- }
- }
- }
- }
-
- companion object {
- const val DEBUG = false
-
- private const val RECEIVER_EXPORTED = 0x2
- private const val RECEIVER_NOT_EXPORTED = 0x4
- private const val RECEIVER_EXPORTED_FLAG_PRESENT_MASK =
- RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED
-
- @JvmField
- val ISSUE_RECEIVER_EXPORTED_FLAG: Issue = Issue.create(
- id = "UnspecifiedRegisterReceiverFlag",
- briefDescription = "Missing `registerReceiver()` exported flag",
- explanation = """
- Apps targeting Android T (SDK 33) and higher must specify either `RECEIVER_EXPORTED` \
- or `RECEIVER_NOT_EXPORTED` when registering a broadcast receiver, unless the \
- receiver is only registered for protected system broadcast actions.
- """,
- category = Category.SECURITY,
- priority = 5,
- severity = Severity.WARNING,
- implementation = Implementation(
- RegisterReceiverFlagDetector::class.java,
- Scope.JAVA_FILE_SCOPE
- )
- )
-
- val PROTECTED_BROADCASTS = listOf(
- "android.intent.action.SCREEN_OFF",
- "android.intent.action.SCREEN_ON",
- "android.intent.action.USER_PRESENT",
- "android.intent.action.TIME_SET",
- "android.intent.action.TIME_TICK",
- "android.intent.action.TIMEZONE_CHANGED",
- "android.intent.action.DATE_CHANGED",
- "android.intent.action.PRE_BOOT_COMPLETED",
- "android.intent.action.BOOT_COMPLETED",
- "android.intent.action.PACKAGE_INSTALL",
- "android.intent.action.PACKAGE_ADDED",
- "android.intent.action.PACKAGE_REPLACED",
- "android.intent.action.MY_PACKAGE_REPLACED",
- "android.intent.action.PACKAGE_REMOVED",
- "android.intent.action.PACKAGE_REMOVED_INTERNAL",
- "android.intent.action.PACKAGE_FULLY_REMOVED",
- "android.intent.action.PACKAGE_CHANGED",
- "android.intent.action.PACKAGE_FULLY_LOADED",
- "android.intent.action.PACKAGE_ENABLE_ROLLBACK",
- "android.intent.action.CANCEL_ENABLE_ROLLBACK",
- "android.intent.action.ROLLBACK_COMMITTED",
- "android.intent.action.PACKAGE_RESTARTED",
- "android.intent.action.PACKAGE_DATA_CLEARED",
- "android.intent.action.PACKAGE_FIRST_LAUNCH",
- "android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION",
- "android.intent.action.PACKAGE_NEEDS_VERIFICATION",
- "android.intent.action.PACKAGE_VERIFIED",
- "android.intent.action.PACKAGES_SUSPENDED",
- "android.intent.action.PACKAGES_UNSUSPENDED",
- "android.intent.action.PACKAGES_SUSPENSION_CHANGED",
- "android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY",
- "android.intent.action.DISTRACTING_PACKAGES_CHANGED",
- "android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED",
- "android.intent.action.UID_REMOVED",
- "android.intent.action.QUERY_PACKAGE_RESTART",
- "android.intent.action.CONFIGURATION_CHANGED",
- "android.intent.action.SPLIT_CONFIGURATION_CHANGED",
- "android.intent.action.LOCALE_CHANGED",
- "android.intent.action.APPLICATION_LOCALE_CHANGED",
- "android.intent.action.BATTERY_CHANGED",
- "android.intent.action.BATTERY_LEVEL_CHANGED",
- "android.intent.action.BATTERY_LOW",
- "android.intent.action.BATTERY_OKAY",
- "android.intent.action.ACTION_POWER_CONNECTED",
- "android.intent.action.ACTION_POWER_DISCONNECTED",
- "android.intent.action.ACTION_SHUTDOWN",
- "android.intent.action.CHARGING",
- "android.intent.action.DISCHARGING",
- "android.intent.action.DEVICE_STORAGE_LOW",
- "android.intent.action.DEVICE_STORAGE_OK",
- "android.intent.action.DEVICE_STORAGE_FULL",
- "android.intent.action.DEVICE_STORAGE_NOT_FULL",
- "android.intent.action.NEW_OUTGOING_CALL",
- "android.intent.action.REBOOT",
- "android.intent.action.DOCK_EVENT",
- "android.intent.action.THERMAL_EVENT",
- "android.intent.action.MASTER_CLEAR_NOTIFICATION",
- "android.intent.action.USER_ADDED",
- "android.intent.action.USER_REMOVED",
- "android.intent.action.USER_STARTING",
- "android.intent.action.USER_STARTED",
- "android.intent.action.USER_STOPPING",
- "android.intent.action.USER_STOPPED",
- "android.intent.action.USER_BACKGROUND",
- "android.intent.action.USER_FOREGROUND",
- "android.intent.action.USER_SWITCHED",
- "android.intent.action.USER_INITIALIZE",
- "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION",
- "android.intent.action.DOMAINS_NEED_VERIFICATION",
- "android.intent.action.OVERLAY_ADDED",
- "android.intent.action.OVERLAY_CHANGED",
- "android.intent.action.OVERLAY_REMOVED",
- "android.intent.action.OVERLAY_PRIORITY_CHANGED",
- "android.intent.action.MY_PACKAGE_SUSPENDED",
- "android.intent.action.MY_PACKAGE_UNSUSPENDED",
- "android.os.action.POWER_SAVE_MODE_CHANGED",
- "android.os.action.DEVICE_IDLE_MODE_CHANGED",
- "android.os.action.POWER_SAVE_WHITELIST_CHANGED",
- "android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED",
- "android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL",
- "android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED",
- "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED",
- "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED",
- "android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL",
- "android.app.action.ENTER_CAR_MODE",
- "android.app.action.EXIT_CAR_MODE",
- "android.app.action.ENTER_CAR_MODE_PRIORITIZED",
- "android.app.action.EXIT_CAR_MODE_PRIORITIZED",
- "android.app.action.ENTER_DESK_MODE",
- "android.app.action.EXIT_DESK_MODE",
- "android.app.action.NEXT_ALARM_CLOCK_CHANGED",
- "android.app.action.USER_ADDED",
- "android.app.action.USER_REMOVED",
- "android.app.action.USER_STARTED",
- "android.app.action.USER_STOPPED",
- "android.app.action.USER_SWITCHED",
- "android.app.action.BUGREPORT_SHARING_DECLINED",
- "android.app.action.BUGREPORT_FAILED",
- "android.app.action.BUGREPORT_SHARE",
- "android.app.action.SHOW_DEVICE_MONITORING_DIALOG",
- "android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED",
- "android.intent.action.INCIDENT_REPORT_READY",
- "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS",
- "android.appwidget.action.APPWIDGET_DELETED",
- "android.appwidget.action.APPWIDGET_DISABLED",
- "android.appwidget.action.APPWIDGET_ENABLED",
- "android.appwidget.action.APPWIDGET_HOST_RESTORED",
- "android.appwidget.action.APPWIDGET_RESTORED",
- "android.appwidget.action.APPWIDGET_ENABLE_AND_UPDATE",
- "android.os.action.SETTING_RESTORED",
- "android.app.backup.intent.CLEAR",
- "android.app.backup.intent.INIT",
- "android.bluetooth.intent.DISCOVERABLE_TIMEOUT",
- "android.bluetooth.adapter.action.STATE_CHANGED",
- "android.bluetooth.adapter.action.SCAN_MODE_CHANGED",
- "android.bluetooth.adapter.action.DISCOVERY_STARTED",
- "android.bluetooth.adapter.action.DISCOVERY_FINISHED",
- "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED",
- "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED",
- "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.device.action.UUID",
- "android.bluetooth.device.action.MAS_INSTANCE",
- "android.bluetooth.device.action.ALIAS_CHANGED",
- "android.bluetooth.device.action.FOUND",
- "android.bluetooth.device.action.CLASS_CHANGED",
- "android.bluetooth.device.action.ACL_CONNECTED",
- "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED",
- "android.bluetooth.device.action.ACL_DISCONNECTED",
- "android.bluetooth.device.action.NAME_CHANGED",
- "android.bluetooth.device.action.BOND_STATE_CHANGED",
- "android.bluetooth.device.action.NAME_FAILED",
- "android.bluetooth.device.action.PAIRING_REQUEST",
- "android.bluetooth.device.action.PAIRING_CANCEL",
- "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY",
- "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL",
- "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST",
- "android.bluetooth.device.action.SDP_RECORD",
- "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED",
- "android.bluetooth.devicepicker.action.LAUNCH",
- "android.bluetooth.devicepicker.action.DEVICE_SELECTED",
- "android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED",
- "android.bluetooth.action.CSIS_DEVICE_AVAILABLE",
- "android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE",
- "android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED",
- "android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY",
- "android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY",
- "android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED",
- "android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED",
- "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED",
- "android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED",
- "android.bluetooth.action.LE_AUDIO_CONF_CHANGED",
- "android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED",
- "android.bluetooth.action.LE_AUDIO_GROUP_STATUS_CHANGED",
- "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED",
- "android.btopp.intent.action.INCOMING_FILE_NOTIFICATION",
- "android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT",
- "android.btopp.intent.action.LIST",
- "android.btopp.intent.action.OPEN_OUTBOUND",
- "android.btopp.intent.action.HIDE_COMPLETE",
- "android.btopp.intent.action.CONFIRM",
- "android.btopp.intent.action.HIDE",
- "android.btopp.intent.action.RETRY",
- "android.btopp.intent.action.OPEN",
- "android.btopp.intent.action.OPEN_INBOUND",
- "android.btopp.intent.action.TRANSFER_COMPLETE",
- "android.btopp.intent.action.ACCEPT",
- "android.btopp.intent.action.DECLINE",
- "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN",
- "com.android.bluetooth.pbap.authchall",
- "com.android.bluetooth.pbap.userconfirmtimeout",
- "com.android.bluetooth.pbap.authresponse",
- "com.android.bluetooth.pbap.authcancelled",
- "com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT",
- "com.android.bluetooth.sap.action.DISCONNECT_ACTION",
- "android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED",
- "android.hardware.usb.action.USB_STATE",
- "android.hardware.usb.action.USB_PORT_CHANGED",
- "android.hardware.usb.action.USB_ACCESSORY_ATTACHED",
- "android.hardware.usb.action.USB_ACCESSORY_DETACHED",
- "android.hardware.usb.action.USB_ACCESSORY_HANDSHAKE",
- "android.hardware.usb.action.USB_DEVICE_ATTACHED",
- "android.hardware.usb.action.USB_DEVICE_DETACHED",
- "android.intent.action.HEADSET_PLUG",
- "android.media.action.HDMI_AUDIO_PLUG",
- "android.media.action.MICROPHONE_MUTE_CHANGED",
- "android.media.action.SPEAKERPHONE_STATE_CHANGED",
- "android.media.AUDIO_BECOMING_NOISY",
- "android.media.RINGER_MODE_CHANGED",
- "android.media.VIBRATE_SETTING_CHANGED",
- "android.media.VOLUME_CHANGED_ACTION",
- "android.media.MASTER_VOLUME_CHANGED_ACTION",
- "android.media.MASTER_MUTE_CHANGED_ACTION",
- "android.media.MASTER_MONO_CHANGED_ACTION",
- "android.media.MASTER_BALANCE_CHANGED_ACTION",
- "android.media.SCO_AUDIO_STATE_CHANGED",
- "android.media.ACTION_SCO_AUDIO_STATE_UPDATED",
- "android.intent.action.MEDIA_REMOVED",
- "android.intent.action.MEDIA_UNMOUNTED",
- "android.intent.action.MEDIA_CHECKING",
- "android.intent.action.MEDIA_NOFS",
- "android.intent.action.MEDIA_MOUNTED",
- "android.intent.action.MEDIA_SHARED",
- "android.intent.action.MEDIA_UNSHARED",
- "android.intent.action.MEDIA_BAD_REMOVAL",
- "android.intent.action.MEDIA_UNMOUNTABLE",
- "android.intent.action.MEDIA_EJECT",
- "android.net.conn.CAPTIVE_PORTAL",
- "android.net.conn.CONNECTIVITY_CHANGE",
- "android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE",
- "android.net.conn.DATA_ACTIVITY_CHANGE",
- "android.net.conn.RESTRICT_BACKGROUND_CHANGED",
- "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED",
- "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED",
- "android.net.nsd.STATE_CHANGED",
- "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED",
- "android.nfc.action.ADAPTER_STATE_CHANGED",
- "android.nfc.action.PREFERRED_PAYMENT_CHANGED",
- "android.nfc.action.TRANSACTION_DETECTED",
- "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC",
- "com.android.nfc.action.LLCP_UP",
- "com.android.nfc.action.LLCP_DOWN",
- "com.android.nfc.cardemulation.action.CLOSE_TAP_DIALOG",
- "com.android.nfc.handover.action.ALLOW_CONNECT",
- "com.android.nfc.handover.action.DENY_CONNECT",
- "com.android.nfc.handover.action.TIMEOUT_CONNECT",
- "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED",
- "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED",
- "com.android.nfc_extras.action.AID_SELECTED",
- "android.btopp.intent.action.WHITELIST_DEVICE",
- "android.btopp.intent.action.STOP_HANDOVER_TRANSFER",
- "android.nfc.handover.intent.action.HANDOVER_SEND",
- "android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE",
- "com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER",
- "android.net.action.CLEAR_DNS_CACHE",
- "android.intent.action.PROXY_CHANGE",
- "android.os.UpdateLock.UPDATE_LOCK_CHANGED",
- "android.intent.action.DREAMING_STARTED",
- "android.intent.action.DREAMING_STOPPED",
- "android.intent.action.ANY_DATA_STATE",
- "com.android.server.stats.action.TRIGGER_COLLECTION",
- "com.android.server.WifiManager.action.START_SCAN",
- "com.android.server.WifiManager.action.START_PNO",
- "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP",
- "com.android.server.WifiManager.action.DEVICE_IDLE",
- "com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED",
- "com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED",
- "com.android.internal.action.EUICC_FACTORY_RESET",
- "com.android.server.usb.ACTION_OPEN_IN_APPS",
- "com.android.server.am.DELETE_DUMPHEAP",
- "com.android.server.net.action.SNOOZE_WARNING",
- "com.android.server.net.action.SNOOZE_RAPID",
- "com.android.server.wifi.ACTION_SHOW_SET_RANDOMIZATION_DETAILS",
- "com.android.server.wifi.action.NetworkSuggestion.USER_ALLOWED_APP",
- "com.android.server.wifi.action.NetworkSuggestion.USER_DISALLOWED_APP",
- "com.android.server.wifi.action.NetworkSuggestion.USER_DISMISSED",
- "com.android.server.wifi.action.CarrierNetwork.USER_ALLOWED_CARRIER",
- "com.android.server.wifi.action.CarrierNetwork.USER_DISALLOWED_CARRIER",
- "com.android.server.wifi.action.CarrierNetwork.USER_DISMISSED",
- "com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION",
- "com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK",
- "com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK",
- "com.android.server.wifi.ConnectToNetworkNotification.PICK_NETWORK_AFTER_FAILURE",
- "com.android.server.wifi.wakeup.DISMISS_NOTIFICATION",
- "com.android.server.wifi.wakeup.OPEN_WIFI_PREFERENCES",
- "com.android.server.wifi.wakeup.OPEN_WIFI_SETTINGS",
- "com.android.server.wifi.wakeup.TURN_OFF_WIFI_WAKE",
- "android.net.wifi.WIFI_STATE_CHANGED",
- "android.net.wifi.WIFI_AP_STATE_CHANGED",
- "android.net.wifi.WIFI_CREDENTIAL_CHANGED",
- "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED",
- "android.net.wifi.aware.action.WIFI_AWARE_RESOURCE_CHANGED",
- "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED",
- "android.net.wifi.SCAN_RESULTS",
- "android.net.wifi.RSSI_CHANGED",
- "android.net.wifi.STATE_CHANGE",
- "android.net.wifi.LINK_CONFIGURATION_CHANGED",
- "android.net.wifi.CONFIGURED_NETWORKS_CHANGE",
- "android.net.wifi.action.NETWORK_SETTINGS_RESET",
- "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT",
- "android.net.wifi.action.PASSPOINT_ICON",
- "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST",
- "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION",
- "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW",
- "android.net.wifi.action.REFRESH_USER_PROVISIONING",
- "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION",
- "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED",
- "android.net.wifi.supplicant.CONNECTION_CHANGE",
- "android.net.wifi.supplicant.STATE_CHANGE",
- "android.net.wifi.p2p.STATE_CHANGED",
- "android.net.wifi.p2p.DISCOVERY_STATE_CHANGE",
- "android.net.wifi.p2p.THIS_DEVICE_CHANGED",
- "android.net.wifi.p2p.PEERS_CHANGED",
- "android.net.wifi.p2p.CONNECTION_STATE_CHANGE",
- "android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED",
- "android.net.conn.TETHER_STATE_CHANGED",
- "android.net.conn.INET_CONDITION_ACTION",
- "android.net.conn.NETWORK_CONDITIONS_MEASURED",
- "android.net.scoring.SCORE_NETWORKS",
- "android.net.scoring.SCORER_CHANGED",
- "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE",
- "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE",
- "android.intent.action.AIRPLANE_MODE",
- "android.intent.action.ADVANCED_SETTINGS",
- "android.intent.action.APPLICATION_RESTRICTIONS_CHANGED",
- "com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES",
- "com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT",
- "com.android.server.adb.WIRELESS_DEBUG_STATUS",
- "android.intent.action.ACTION_IDLE_MAINTENANCE_START",
- "android.intent.action.ACTION_IDLE_MAINTENANCE_END",
- "com.android.server.ACTION_TRIGGER_IDLE",
- "android.intent.action.HDMI_PLUGGED",
- "android.intent.action.PHONE_STATE",
- "android.intent.action.SUB_DEFAULT_CHANGED",
- "android.location.PROVIDERS_CHANGED",
- "android.location.MODE_CHANGED",
- "android.location.action.GNSS_CAPABILITIES_CHANGED",
- "android.net.proxy.PAC_REFRESH",
- "android.telecom.action.DEFAULT_DIALER_CHANGED",
- "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED",
- "android.provider.action.SMS_MMS_DB_CREATED",
- "android.provider.action.SMS_MMS_DB_LOST",
- "android.intent.action.CONTENT_CHANGED",
- "android.provider.Telephony.MMS_DOWNLOADED",
- "android.content.action.PERMISSION_RESPONSE_RECEIVED",
- "android.content.action.REQUEST_PERMISSION",
- "android.nfc.handover.intent.action.HANDOVER_STARTED",
- "android.nfc.handover.intent.action.TRANSFER_DONE",
- "android.nfc.handover.intent.action.TRANSFER_PROGRESS",
- "android.nfc.handover.intent.action.TRANSFER_DONE",
- "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED",
- "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED",
- "android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE",
- "android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED",
- "android.internal.policy.action.BURN_IN_PROTECTION",
- "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED",
- "android.app.action.RESET_PROTECTION_POLICY_CHANGED",
- "android.app.action.DEVICE_OWNER_CHANGED",
- "android.app.action.MANAGED_USER_CREATED",
- "android.intent.action.ANR",
- "android.intent.action.CALL",
- "android.intent.action.CALL_PRIVILEGED",
- "android.intent.action.DROPBOX_ENTRY_ADDED",
- "android.intent.action.INPUT_METHOD_CHANGED",
- "android.intent.action.internal_sim_state_changed",
- "android.intent.action.LOCKED_BOOT_COMPLETED",
- "android.intent.action.PRECISE_CALL_STATE",
- "android.intent.action.SUBSCRIPTION_PHONE_STATE",
- "android.intent.action.USER_INFO_CHANGED",
- "android.intent.action.USER_UNLOCKED",
- "android.intent.action.WALLPAPER_CHANGED",
- "android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED",
- "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS",
- "android.app.action.DEVICE_ADMIN_DISABLED",
- "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED",
- "android.app.action.DEVICE_ADMIN_ENABLED",
- "android.app.action.LOCK_TASK_ENTERING",
- "android.app.action.LOCK_TASK_EXITING",
- "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE",
- "android.app.action.ACTION_PASSWORD_CHANGED",
- "android.app.action.ACTION_PASSWORD_EXPIRING",
- "android.app.action.ACTION_PASSWORD_FAILED",
- "android.app.action.ACTION_PASSWORD_SUCCEEDED",
- "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION",
- "com.android.server.ACTION_PROFILE_OFF_DEADLINE",
- "com.android.server.ACTION_TURN_PROFILE_ON_NOTIFICATION",
- "android.intent.action.MANAGED_PROFILE_ADDED",
- "android.intent.action.MANAGED_PROFILE_UNLOCKED",
- "android.intent.action.MANAGED_PROFILE_REMOVED",
- "android.app.action.MANAGED_PROFILE_PROVISIONED",
- "android.bluetooth.adapter.action.BLE_STATE_CHANGED",
- "com.android.bluetooth.map.USER_CONFIRM_TIMEOUT",
- "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT",
- "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY",
- "android.content.jobscheduler.JOB_DELAY_EXPIRED",
- "android.content.syncmanager.SYNC_ALARM",
- "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION",
- "android.media.STREAM_DEVICES_CHANGED_ACTION",
- "android.media.STREAM_MUTE_CHANGED_ACTION",
- "android.net.sip.SIP_SERVICE_UP",
- "android.nfc.action.ADAPTER_STATE_CHANGED",
- "android.os.action.CHARGING",
- "android.os.action.DISCHARGING",
- "android.search.action.SEARCHABLES_CHANGED",
- "android.security.STORAGE_CHANGED",
- "android.security.action.TRUST_STORE_CHANGED",
- "android.security.action.KEYCHAIN_CHANGED",
- "android.security.action.KEY_ACCESS_CHANGED",
- "android.telecom.action.NUISANCE_CALL_STATUS_CHANGED",
- "android.telecom.action.PHONE_ACCOUNT_REGISTERED",
- "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED",
- "android.telecom.action.POST_CALL",
- "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION",
- "android.telephony.action.CARRIER_CONFIG_CHANGED",
- "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED",
- "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED",
- "android.telephony.action.SECRET_CODE",
- "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION",
- "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED",
- "com.android.bluetooth.btservice.action.ALARM_WAKEUP",
- "com.android.server.action.NETWORK_STATS_POLL",
- "com.android.server.action.NETWORK_STATS_UPDATED",
- "com.android.server.timedetector.NetworkTimeUpdateService.action.POLL",
- "com.android.server.telecom.intent.action.CALLS_ADD_ENTRY",
- "com.android.settings.location.MODE_CHANGING",
- "com.android.settings.bluetooth.ACTION_DISMISS_PAIRING",
- "com.android.settings.network.DELETE_SUBSCRIPTION",
- "com.android.settings.network.SWITCH_TO_SUBSCRIPTION",
- "com.android.settings.wifi.action.NETWORK_REQUEST",
- "NotificationManagerService.TIMEOUT",
- "NotificationHistoryDatabase.CLEANUP",
- "ScheduleConditionProvider.EVALUATE",
- "EventConditionProvider.EVALUATE",
- "SnoozeHelper.EVALUATE",
- "wifi_scan_available",
- "action.cne.started",
- "android.content.jobscheduler.JOB_DEADLINE_EXPIRED",
- "android.intent.action.ACTION_UNSOL_RESPONSE_OEM_HOOK_RAW",
- "android.net.conn.CONNECTIVITY_CHANGE_SUPL",
- "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED",
- "android.os.storage.action.VOLUME_STATE_CHANGED",
- "android.os.storage.action.DISK_SCANNED",
- "com.android.server.action.UPDATE_TWILIGHT_STATE",
- "com.android.server.action.RESET_TWILIGHT_AUTO",
- "com.android.server.device_idle.STEP_IDLE_STATE",
- "com.android.server.device_idle.STEP_LIGHT_IDLE_STATE",
- "com.android.server.Wifi.action.TOGGLE_PNO",
- "intent.action.ACTION_RF_BAND_INFO",
- "android.intent.action.MEDIA_RESOURCE_GRANTED",
- "android.app.action.NETWORK_LOGS_AVAILABLE",
- "android.app.action.SECURITY_LOGS_AVAILABLE",
- "android.app.action.COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED",
- "android.app.action.INTERRUPTION_FILTER_CHANGED",
- "android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL",
- "android.app.action.NOTIFICATION_POLICY_CHANGED",
- "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED",
- "android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED",
- "android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED",
- "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED",
- "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED",
- "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED",
- "android.app.action.APP_BLOCK_STATE_CHANGED",
- "android.permission.GET_APP_GRANTED_URI_PERMISSIONS",
- "android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS",
- "android.intent.action.DYNAMIC_SENSOR_CHANGED",
- "android.accounts.LOGIN_ACCOUNTS_CHANGED",
- "android.accounts.action.ACCOUNT_REMOVED",
- "android.accounts.action.VISIBLE_ACCOUNTS_CHANGED",
- "com.android.sync.SYNC_CONN_STATUS_CHANGED",
- "android.net.sip.action.SIP_INCOMING_CALL",
- "com.android.phone.SIP_ADD_PHONE",
- "android.net.sip.action.SIP_REMOVE_PROFILE",
- "android.net.sip.action.SIP_SERVICE_UP",
- "android.net.sip.action.SIP_CALL_OPTION_CHANGED",
- "android.net.sip.action.START_SIP",
- "android.bluetooth.adapter.action.BLE_ACL_CONNECTED",
- "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED",
- "android.bluetooth.input.profile.action.HANDSHAKE",
- "android.bluetooth.input.profile.action.REPORT",
- "android.intent.action.TWILIGHT_CHANGED",
- "com.android.server.fingerprint.ACTION_LOCKOUT_RESET",
- "android.net.wifi.PASSPOINT_ICON_RECEIVED",
- "com.android.server.notification.CountdownConditionProvider",
- "android.server.notification.action.ENABLE_NAS",
- "android.server.notification.action.DISABLE_NAS",
- "android.server.notification.action.LEARNMORE_NAS",
- "com.android.internal.location.ALARM_WAKEUP",
- "com.android.internal.location.ALARM_TIMEOUT",
- "android.intent.action.GLOBAL_BUTTON",
- "android.intent.action.MANAGED_PROFILE_AVAILABLE",
- "android.intent.action.MANAGED_PROFILE_UNAVAILABLE",
- "com.android.server.pm.DISABLE_QUIET_MODE_AFTER_UNLOCK",
- "android.intent.action.PROFILE_ACCESSIBLE",
- "android.intent.action.PROFILE_INACCESSIBLE",
- "com.android.server.retaildemo.ACTION_RESET_DEMO",
- "android.intent.action.DEVICE_LOCKED_CHANGED",
- "com.android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED",
- "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED",
- "com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION",
- "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED",
- "android.content.pm.action.SESSION_COMMITTED",
- "android.os.action.USER_RESTRICTIONS_CHANGED",
- "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT",
- "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED",
- "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED",
- "android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED",
- "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER",
- "com.android.intent.action.timezone.RULES_UPDATE_OPERATION",
- "com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK",
- "android.intent.action.GET_RESTRICTION_ENTRIES",
- "android.telephony.euicc.action.OTA_STATUS_CHANGED",
- "android.app.action.PROFILE_OWNER_CHANGED",
- "android.app.action.TRANSFER_OWNERSHIP_COMPLETE",
- "android.app.action.AFFILIATED_PROFILE_TRANSFER_OWNERSHIP_COMPLETE",
- "android.app.action.STATSD_STARTED",
- "com.android.server.biometrics.fingerprint.ACTION_LOCKOUT_RESET",
- "com.android.server.biometrics.face.ACTION_LOCKOUT_RESET",
- "android.intent.action.DOCK_IDLE",
- "android.intent.action.DOCK_ACTIVE",
- "android.content.pm.action.SESSION_UPDATED",
- "android.settings.action.GRAYSCALE_CHANGED",
- "com.android.server.jobscheduler.GARAGE_MODE_ON",
- "com.android.server.jobscheduler.GARAGE_MODE_OFF",
- "com.android.server.jobscheduler.FORCE_IDLE",
- "com.android.server.jobscheduler.UNFORCE_IDLE",
- "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL",
- "android.intent.action.DEVICE_CUSTOMIZATION_READY",
- "android.app.action.RESET_PROTECTION_POLICY_CHANGED",
- "com.android.internal.intent.action.BUGREPORT_REQUESTED",
- "android.scheduling.action.REBOOT_READY",
- "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED",
- "android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED",
- "android.app.action.SHOW_NEW_USER_DISCLAIMER",
- "android.telecom.action.CURRENT_TTY_MODE_CHANGED",
- "android.intent.action.SERVICE_STATE",
- "android.intent.action.RADIO_TECHNOLOGY",
- "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED",
- "android.intent.action.EMERGENCY_CALL_STATE_CHANGED",
- "android.intent.action.SIG_STR",
- "android.intent.action.ANY_DATA_STATE",
- "android.intent.action.DATA_STALL_DETECTED",
- "android.intent.action.SIM_STATE_CHANGED",
- "android.intent.action.USER_ACTIVITY_NOTIFICATION",
- "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS",
- "android.intent.action.ACTION_MDN_STATE_CHANGED",
- "android.telephony.action.SERVICE_PROVIDERS_UPDATED",
- "android.provider.Telephony.SIM_FULL",
- "com.android.internal.telephony.carrier_key_download_alarm",
- "com.android.internal.telephony.data-restart-trysetup",
- "com.android.internal.telephony.data-stall",
- "com.android.internal.telephony.provisioning_apn_alarm",
- "android.intent.action.DATA_SMS_RECEIVED",
- "android.provider.Telephony.SMS_RECEIVED",
- "android.provider.Telephony.SMS_DELIVER",
- "android.provider.Telephony.SMS_REJECTED",
- "android.provider.Telephony.WAP_PUSH_DELIVER",
- "android.provider.Telephony.WAP_PUSH_RECEIVED",
- "android.provider.Telephony.SMS_CB_RECEIVED",
- "android.provider.action.SMS_EMERGENCY_CB_RECEIVED",
- "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED",
- "android.provider.Telephony.SECRET_CODE",
- "com.android.internal.stk.command",
- "com.android.internal.stk.session_end",
- "com.android.internal.stk.icc_status_change",
- "com.android.internal.stk.alpha_notify",
- "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED",
- "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED",
- "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE",
- "com.android.internal.telephony.CARRIER_SIGNAL_RESET",
- "com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE",
- "com.android.internal.telephony.PROVISION",
- "com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED",
- "com.android.internal.provider.action.VOICEMAIL_SMS_RECEIVED",
- "com.android.intent.isim_refresh",
- "com.android.ims.ACTION_RCS_SERVICE_AVAILABLE",
- "com.android.ims.ACTION_RCS_SERVICE_UNAVAILABLE",
- "com.android.ims.ACTION_RCS_SERVICE_DIED",
- "com.android.ims.ACTION_PRESENCE_CHANGED",
- "com.android.ims.ACTION_PUBLISH_STATUS_CHANGED",
- "com.android.ims.IMS_SERVICE_UP",
- "com.android.ims.IMS_SERVICE_DOWN",
- "com.android.ims.IMS_INCOMING_CALL",
- "com.android.ims.internal.uce.UCE_SERVICE_UP",
- "com.android.ims.internal.uce.UCE_SERVICE_DOWN",
- "com.android.imsconnection.DISCONNECTED",
- "com.android.intent.action.IMS_FEATURE_CHANGED",
- "com.android.intent.action.IMS_CONFIG_CHANGED",
- "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR",
- "com.android.phone.vvm.omtp.sms.REQUEST_SENT",
- "com.android.phone.vvm.ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT",
- "com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED",
- "com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO",
- "com.android.internal.telephony.ACTION_CARRIER_CERTIFICATE_DOWNLOAD",
- "com.android.internal.telephony.action.COUNTRY_OVERRIDE",
- "com.android.internal.telephony.OPEN_DEFAULT_SMS_APP",
- "com.android.internal.telephony.ACTION_TEST_OVERRIDE_CARRIER_ID",
- "android.telephony.action.SIM_CARD_STATE_CHANGED",
- "android.telephony.action.SIM_APPLICATION_STATE_CHANGED",
- "android.telephony.action.SIM_SLOT_STATUS_CHANGED",
- "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED",
- "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED",
- "android.telephony.action.TOGGLE_PROVISION",
- "android.telephony.action.NETWORK_COUNTRY_CHANGED",
- "android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED",
- "android.telephony.action.MULTI_SIM_CONFIG_CHANGED",
- "android.telephony.action.CARRIER_SIGNAL_RESET",
- "android.telephony.action.CARRIER_SIGNAL_PCO_VALUE",
- "android.telephony.action.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE",
- "android.telephony.action.CARRIER_SIGNAL_REDIRECTED",
- "android.telephony.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED",
- "com.android.phone.settings.CARRIER_PROVISIONING",
- "com.android.phone.settings.TRIGGER_CARRIER_PROVISIONING",
- "com.android.internal.telephony.ACTION_VOWIFI_ENABLED",
- "android.telephony.action.ANOMALY_REPORTED",
- "android.intent.action.SUBSCRIPTION_INFO_RECORD_ADDED",
- "android.intent.action.ACTION_MANAGED_ROAMING_IND",
- "android.telephony.ims.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE",
- "android.safetycenter.action.REFRESH_SAFETY_SOURCES",
- "android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED",
- "android.app.action.DEVICE_POLICY_RESOURCE_UPDATED",
- "android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER",
- "android.service.autofill.action.DELAYED_FILL",
- "android.app.action.PROVISIONING_COMPLETED",
- "android.app.action.LOST_MODE_LOCATION_UPDATE",
- "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED",
- "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT",
- "android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED",
- "android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED",
- "android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED",
- "android.bluetooth.headsetclient.profile.action.AG_EVENT",
- "android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED",
- "android.bluetooth.headsetclient.profile.action.RESULT",
- "android.bluetooth.headsetclient.profile.action.LAST_VTAG",
- "android.bluetooth.headsetclient.profile.action.NETWORK_SERVICE_STATE_CHANGED",
- "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED",
- "android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED",
- "android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED",
- "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED",
- "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED",
- "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED",
- "android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED",
- "android.bluetooth.avrcp-controller.profile.action.BROWSE_CONNECTION_STATE_CHANGED",
- "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.avrcp-controller.profile.action.FOLDER_LIST",
- "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT",
- "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.input.profile.action.IDLE_TIME_CHANGED",
- "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED",
- "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS",
- "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED",
- "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT",
- "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY",
- "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED",
- "android.bluetooth.action.TETHERING_STATE_CHANGED",
- "com.android.internal.action.EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS",
- "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED",
- "com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION",
- "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM"
- )
- }
-}
diff --git a/tools/lint/framework/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt
deleted file mode 100644
index 7c0ebca4ec1e..000000000000
--- a/tools/lint/framework/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- * Copyright (C) 2021 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.google.android.lint
-
-import com.android.tools.lint.checks.infrastructure.LintDetectorTest
-import com.android.tools.lint.checks.infrastructure.TestFile
-import com.android.tools.lint.checks.infrastructure.TestLintTask
-import com.android.tools.lint.detector.api.Detector
-import com.android.tools.lint.detector.api.Issue
-
-@Suppress("UnstableApiUsage")
-class RegisterReceiverFlagDetectorTest : LintDetectorTest() {
-
- override fun getDetector(): Detector = RegisterReceiverFlagDetector()
-
- override fun getIssues(): List<Issue> = listOf(
- RegisterReceiverFlagDetector.ISSUE_RECEIVER_EXPORTED_FLAG
- )
-
- override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
-
- fun testProtectedBroadcast() {
- lint().files(
- java(
- """
- package test.pkg;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- public class TestClass1 {
- public void testMethod(Context context, BroadcastReceiver receiver) {
- IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- context.registerReceiver(receiver, filter);
- }
- }
- """
- ).indented(),
- *stubs
- )
- .run()
- .expectClean()
- }
-
- fun testProtectedBroadcastCreate() {
- lint().files(
- java(
- """
- package test.pkg;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- public class TestClass1 {
- public void testMethod(Context context, BroadcastReceiver receiver) {
- IntentFilter filter =
- IntentFilter.create(Intent.ACTION_BATTERY_CHANGED, "foo/bar");
- context.registerReceiver(receiver, filter);
- }
- }
- """
- ).indented(),
- *stubs
- )
- .run()
- .expectClean()
- }
-
- fun testMultipleProtectedBroadcasts() {
- lint().files(
- java(
- """
- package test.pkg;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- public class TestClass1 {
- public void testMethod(Context context, BroadcastReceiver receiver) {
- IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- filter.addAction(Intent.ACTION_BATTERY_LOW);
- filter.addAction(Intent.ACTION_BATTERY_OKAY);
- context.registerReceiver(receiver, filter);
- }
- }
- """
- ).indented(),
- *stubs
- )
- .run()
- .expectClean()
- }
-
- // TODO(b/267510341): Reenable this test
- // fun testSubsequentFilterModification() {
- // lint().files(
- // java(
- // """
- // package test.pkg;
- // import android.content.BroadcastReceiver;
- // import android.content.Context;
- // import android.content.Intent;
- // import android.content.IntentFilter;
- // public class TestClass1 {
- // public void testMethod(Context context, BroadcastReceiver receiver) {
- // IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- // filter.addAction(Intent.ACTION_BATTERY_LOW);
- // filter.addAction(Intent.ACTION_BATTERY_OKAY);
- // context.registerReceiver(receiver, filter);
- // filter.addAction("querty");
- // context.registerReceiver(receiver, filter);
- // }
- // }
- // """
- // ).indented(),
- // *stubs
- // )
- // .run()
- // .expect("""
- // src/test/pkg/TestClass1.java:13: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
- // context.registerReceiver(receiver, filter);
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // 0 errors, 1 warnings
- // """.trimIndent())
- // }
-
- fun testNullReceiver() {
- lint().files(
- java(
- """
- package test.pkg;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- public class TestClass1 {
- public void testMethod(Context context) {
- IntentFilter filter = new IntentFilter("qwerty");
- context.registerReceiver(null, filter);
- }
- }
- """
- ).indented(),
- *stubs
- )
- .run()
- .expectClean()
- }
-
- fun testExportedFlagPresent() {
- lint().files(
- java(
- """
- package test.pkg;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- public class TestClass1 {
- public void testMethod(Context context, BroadcastReceiver receiver) {
- IntentFilter filter = new IntentFilter("qwerty");
- context.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
- }
- }
- """
- ).indented(),
- *stubs
- )
- .run()
- .expectClean()
- }
-
- fun testNotExportedFlagPresent() {
- lint().files(
- java(
- """
- package test.pkg;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- public class TestClass1 {
- public void testMethod(Context context, BroadcastReceiver receiver) {
- IntentFilter filter = new IntentFilter("qwerty");
- context.registerReceiver(receiver, filter,
- Context.RECEIVER_NOT_EXPORTED);
- }
- }
- """
- ).indented(),
- *stubs
- )
- .run()
- .expectClean()
- }
-
- // TODO(b/267510341): Reenable this test
- // fun testFlagArgumentAbsent() {
- // lint().files(
- // java(
- // """
- // package test.pkg;
- // import android.content.BroadcastReceiver;
- // import android.content.Context;
- // import android.content.Intent;
- // import android.content.IntentFilter;
- // public class TestClass1 {
- // public void testMethod(Context context, BroadcastReceiver receiver) {
- // IntentFilter filter = new IntentFilter("qwerty");
- // context.registerReceiver(receiver, filter);
- // }
- // }
- // """
- // ).indented(),
- // *stubs
- // )
- // .run()
- // .expect("""
- // src/test/pkg/TestClass1.java:9: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
- // context.registerReceiver(receiver, filter);
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // 0 errors, 1 warnings
- // """.trimIndent())
- // }
-
- // TODO(b/267510341): Reenable this test
- // fun testExportedFlagsAbsent() {
- // lint().files(
- // java(
- // """
- // package test.pkg;
- // import android.content.BroadcastReceiver;
- // import android.content.Context;
- // import android.content.Intent;
- // import android.content.IntentFilter;
- // public class TestClass1 {
- // public void testMethod(Context context, BroadcastReceiver receiver) {
- // IntentFilter filter = new IntentFilter("qwerty");
- // context.registerReceiver(receiver, filter, 0);
- // }
- // }
- // """
- // ).indented(),
- // *stubs
- // )
- // .run()
- // .expect("""
- // src/test/pkg/TestClass1.java:9: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
- // context.registerReceiver(receiver, filter, 0);
- // ~
- // 0 errors, 1 warnings
- // """.trimIndent())
- // }
-
- fun testExportedFlagVariable() {
- lint().files(
- java(
- """
- package test.pkg;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- public class TestClass1 {
- public void testMethod(Context context, BroadcastReceiver receiver) {
- IntentFilter filter = new IntentFilter("qwerty");
- var flags = Context.RECEIVER_EXPORTED;
- context.registerReceiver(receiver, filter, flags);
- }
- }
- """
- ).indented(),
- *stubs
- )
- .run()
- .expectClean()
- }
-
- // TODO(b/267510341): Reenable this test
- // fun testUnknownFilter() {
- // lint().files(
- // java(
- // """
- // package test.pkg;
- // import android.content.BroadcastReceiver;
- // import android.content.Context;
- // import android.content.Intent;
- // import android.content.IntentFilter;
- // public class TestClass1 {
- // public void testMethod(Context context, BroadcastReceiver receiver,
- // IntentFilter filter) {
- // context.registerReceiver(receiver, filter);
- // }
- // }
- // """
- // ).indented(),
- // *stubs
- // )
- // .run()
- // .expect("""
- // src/test/pkg/TestClass1.java:9: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
- // context.registerReceiver(receiver, filter);
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // 0 errors, 1 warnings
- // """.trimIndent())
- // }
-
- // TODO(b/267510341): Reenable this test
- // fun testFilterEscapes() {
- // lint().files(
- // java(
- // """
- // package test.pkg;
- // import android.content.BroadcastReceiver;
- // import android.content.Context;
- // import android.content.Intent;
- // import android.content.IntentFilter;
- // public class TestClass1 {
- // public void testMethod(Context context, BroadcastReceiver receiver) {
- // IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- // updateFilter(filter);
- // context.registerReceiver(receiver, filter);
- // }
- // }
- // """
- // ).indented(),
- // *stubs
- // )
- // .run()
- // .expect("""
- // src/test/pkg/TestClass1.java:10: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
- // context.registerReceiver(receiver, filter);
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // 0 errors, 1 warnings
- // """.trimIndent())
- // }
-
- fun testInlineFilter() {
- lint().files(
- java(
- """
- package test.pkg;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- public class TestClass1 {
- public void testMethod(Context context, BroadcastReceiver receiver) {
- context.registerReceiver(receiver,
- new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- }
- }
- """
- ).indented(),
- *stubs
- )
- .run()
- .expectClean()
- }
-
- // TODO(b/267510341): Reenable this test
- // fun testInlineFilterApply() {
- // lint().files(
- // kotlin(
- // """
- // package test.pkg
- // import android.content.BroadcastReceiver
- // import android.content.Context
- // import android.content.Intent
- // import android.content.IntentFilter
- // class TestClass1 {
- // fun test(context: Context, receiver: BroadcastReceiver) {
- // context.registerReceiver(receiver,
- // IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
- // addAction("qwerty")
- // })
- // }
- // }
- // """
- // ).indented(),
- // *stubs
- // )
- // .run()
- // .expect("""
- // src/test/pkg/TestClass1.kt:8: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
- // context.registerReceiver(receiver,
- // ^
- // 0 errors, 1 warnings
- // """.trimIndent())
- // }
-
- // TODO(b/267510341): Reenable this test
- // fun testFilterVariableApply() {
- // lint().files(
- // kotlin(
- // """
- // package test.pkg
- // import android.content.BroadcastReceiver
- // import android.content.Context
- // import android.content.Intent
- // import android.content.IntentFilter
- // class TestClass1 {
- // fun test(context: Context, receiver: BroadcastReceiver) {
- // val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
- // addAction("qwerty")
- // }
- // context.registerReceiver(receiver, filter)
- // }
- // }
- // """
- // ).indented(),
- // *stubs
- // )
- // .run()
- // .expect("""
- // src/test/pkg/TestClass1.kt:11: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
- // context.registerReceiver(receiver, filter)
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // 0 errors, 1 warnings
- // """.trimIndent())
- // }
-
- // TODO(b/267510341): Reenable this test
- // fun testFilterVariableApply2() {
- // lint().files(
- // kotlin(
- // """
- // package test.pkg
- // import android.content.BroadcastReceiver
- // import android.content.Context
- // import android.content.Intent
- // import android.content.IntentFilter
- // class TestClass1 {
- // fun test(context: Context, receiver: BroadcastReceiver) {
- // val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
- // addAction(Intent.ACTION_BATTERY_OKAY)
- // }
- // context.registerReceiver(receiver, filter.apply {
- // addAction("qwerty")
- // })
- // }
- // }
- // """
- // ).indented(),
- // *stubs
- // )
- // .run()
- // .expect("""
- // src/test/pkg/TestClass1.kt:11: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
- // context.registerReceiver(receiver, filter.apply {
- // ^
- // 0 errors, 1 warnings
- // """.trimIndent())
- // }
-
- // TODO(b/267510341): Reenable this test
- // fun testFilterComplexChain() {
- // lint().files(
- // kotlin(
- // """
- // package test.pkg
- // import android.content.BroadcastReceiver
- // import android.content.Context
- // import android.content.Intent
- // import android.content.IntentFilter
- // class TestClass1 {
- // fun test(context: Context, receiver: BroadcastReceiver) {
- // val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
- // addAction(Intent.ACTION_BATTERY_OKAY)
- // }
- // val filter2 = filter
- // val filter3 = filter2.apply {
- // addAction(Intent.ACTION_BATTERY_LOW)
- // }
- // context.registerReceiver(receiver, filter3)
- // val filter4 = filter3.apply {
- // addAction("qwerty")
- // }
- // context.registerReceiver(receiver, filter4)
- // }
- // }
- // """
- // ).indented(),
- // *stubs
- // )
- // .run()
- // .expect("""
- // src/test/pkg/TestClass1.kt:19: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
- // context.registerReceiver(receiver, filter4)
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // 0 errors, 1 warnings
- // """.trimIndent())
- // }
-
- private val broadcastReceiverStub: TestFile = java(
- """
- package android.content;
- public class BroadcastReceiver {
- // Stub
- }
- """
- ).indented()
-
- private val contextStub: TestFile = java(
- """
- package android.content;
- public class Context {
- public static final int RECEIVER_EXPORTED = 0x2;
- public static final int RECEIVER_NOT_EXPORTED = 0x4;
- @Nullable
- public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
- IntentFilter filter,
- @RegisterReceiverFlags int flags);
- }
- """
- ).indented()
-
- private val intentStub: TestFile = java(
- """
- package android.content;
- public class Intent {
- public static final String ACTION_BATTERY_CHANGED =
- "android.intent.action.BATTERY_CHANGED";
- public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
- public static final String ACTION_BATTERY_OKAY =
- "android.intent.action.BATTERY_OKAY";
- }
- """
- ).indented()
-
- private val intentFilterStub: TestFile = java(
- """
- package android.content;
- public class IntentFilter {
- public IntentFilter() {
- // Stub
- }
- public IntentFilter(String action) {
- // Stub
- }
- public IntentFilter(String action, String dataType) {
- // Stub
- }
- public static IntentFilter create(String action, String dataType) {
- return null;
- }
- public final void addAction(String action) {
- // Stub
- }
- }
- """
- ).indented()
-
- private val stubs = arrayOf(broadcastReceiverStub, contextStub, intentStub, intentFilterStub)
-}
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
index 9bfeb6308d13..fe397d9c2662 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.wifi.sharedconnectivity.service.SharedConnectivityService;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
@@ -86,6 +87,7 @@ public final class HotspotNetwork implements Parcelable {
@Nullable
@SecurityType
private final ArraySet<Integer> mHotspotSecurityTypes;
+ private final Bundle mExtras;
/**
* Builder class for {@link HotspotNetwork}.
@@ -102,8 +104,8 @@ public final class HotspotNetwork implements Parcelable {
private String mHotspotBssid;
@Nullable
@SecurityType
- private final ArraySet<Integer> mHotspotSecurityTypes =
- new ArraySet<>();
+ private final ArraySet<Integer> mHotspotSecurityTypes = new ArraySet<>();
+ private Bundle mExtras = Bundle.EMPTY;
/**
* Set the remote device ID.
@@ -190,6 +192,17 @@ public final class HotspotNetwork implements Parcelable {
}
/**
+ * Sets the extras bundle
+ *
+ * @return Returns the Builder object.
+ */
+ @NonNull
+ public Builder setExtras(@NonNull Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
* Builds the {@link HotspotNetwork} object.
*
* @return Returns the built {@link HotspotNetwork} object.
@@ -203,7 +216,8 @@ public final class HotspotNetwork implements Parcelable {
mNetworkName,
mHotspotSsid,
mHotspotBssid,
- mHotspotSecurityTypes);
+ mHotspotSecurityTypes,
+ mExtras);
}
}
@@ -231,7 +245,8 @@ public final class HotspotNetwork implements Parcelable {
@NonNull String networkName,
@Nullable String hotspotSsid,
@Nullable String hotspotBssid,
- @Nullable @SecurityType ArraySet<Integer> hotspotSecurityTypes) {
+ @Nullable @SecurityType ArraySet<Integer> hotspotSecurityTypes,
+ @NonNull Bundle extras) {
validate(deviceId,
networkType,
networkName,
@@ -243,6 +258,7 @@ public final class HotspotNetwork implements Parcelable {
mHotspotSsid = hotspotSsid;
mHotspotBssid = hotspotBssid;
mHotspotSecurityTypes = new ArraySet<>(hotspotSecurityTypes);
+ mExtras = extras;
}
/**
@@ -315,6 +331,16 @@ public final class HotspotNetwork implements Parcelable {
return mHotspotSecurityTypes;
}
+ /**
+ * Gets the extras Bundle.
+ *
+ * @return Returns a Bundle object.
+ */
+ @NonNull
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
@Override
public boolean equals(Object obj) {
if (!(obj instanceof HotspotNetwork)) return false;
@@ -348,6 +374,7 @@ public final class HotspotNetwork implements Parcelable {
dest.writeString(mHotspotSsid);
dest.writeString(mHotspotBssid);
dest.writeArraySet(mHotspotSecurityTypes);
+ dest.writeBundle(mExtras);
}
/**
@@ -359,7 +386,7 @@ public final class HotspotNetwork implements Parcelable {
public static HotspotNetwork readFromParcel(@NonNull Parcel in) {
return new HotspotNetwork(in.readLong(), NetworkProviderInfo.readFromParcel(in),
in.readInt(), in.readString(), in.readString(), in.readString(),
- (ArraySet<Integer>) in.readArraySet(null));
+ (ArraySet<Integer>) in.readArraySet(null), in.readBundle());
}
@NonNull
@@ -385,6 +412,7 @@ public final class HotspotNetwork implements Parcelable {
.append(", hotspotSsid=").append(mHotspotSsid)
.append(", hotspotBssid=").append(mHotspotBssid)
.append(", hotspotSecurityTypes=").append(mHotspotSecurityTypes.toString())
+ .append(", extras=").append(mExtras.toString())
.append("]").toString();
}
}
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java
index 69767f302bd8..72acf2ccab0c 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java
@@ -117,7 +117,7 @@ public final class HotspotNetworkConnectionStatus implements Parcelable {
@ConnectionStatus
private int mStatus;
private HotspotNetwork mHotspotNetwork;
- private Bundle mExtras;
+ private Bundle mExtras = Bundle.EMPTY;
/**
* Sets the status of the connection
@@ -179,7 +179,7 @@ public final class HotspotNetworkConnectionStatus implements Parcelable {
}
private HotspotNetworkConnectionStatus(@ConnectionStatus int status,
- HotspotNetwork hotspotNetwork, Bundle extras) {
+ HotspotNetwork hotspotNetwork, @NonNull Bundle extras) {
validate(status);
mStatus = status;
mHotspotNetwork = hotspotNetwork;
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java
index 64412bc55fb2..c390e42f348e 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java
@@ -22,6 +22,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -73,6 +74,7 @@ public final class KnownNetwork implements Parcelable {
@SecurityType
private final ArraySet<Integer> mSecurityTypes;
private final NetworkProviderInfo mNetworkProviderInfo;
+ private final Bundle mExtras;
/**
* Builder class for {@link KnownNetwork}.
@@ -84,6 +86,7 @@ public final class KnownNetwork implements Parcelable {
@SecurityType
private final ArraySet<Integer> mSecurityTypes = new ArraySet<>();
private NetworkProviderInfo mNetworkProviderInfo;
+ private Bundle mExtras = Bundle.EMPTY;
/**
* Sets the indicated source of the known network.
@@ -135,6 +138,17 @@ public final class KnownNetwork implements Parcelable {
}
/**
+ * Sets the extras bundle
+ *
+ * @return Returns the Builder object.
+ */
+ @NonNull
+ public Builder setExtras(@NonNull Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
* Builds the {@link KnownNetwork} object.
*
* @return Returns the built {@link KnownNetwork} object.
@@ -145,7 +159,8 @@ public final class KnownNetwork implements Parcelable {
mNetworkSource,
mSsid,
mSecurityTypes,
- mNetworkProviderInfo);
+ mNetworkProviderInfo,
+ mExtras);
}
}
@@ -173,12 +188,14 @@ public final class KnownNetwork implements Parcelable {
@NetworkSource int networkSource,
@NonNull String ssid,
@NonNull @SecurityType ArraySet<Integer> securityTypes,
- @Nullable NetworkProviderInfo networkProviderInfo) {
+ @Nullable NetworkProviderInfo networkProviderInfo,
+ @NonNull Bundle extras) {
validate(networkSource, ssid, securityTypes, networkProviderInfo);
mNetworkSource = networkSource;
mSsid = ssid;
mSecurityTypes = new ArraySet<>(securityTypes);
mNetworkProviderInfo = networkProviderInfo;
+ mExtras = extras;
}
/**
@@ -223,6 +240,16 @@ public final class KnownNetwork implements Parcelable {
return mNetworkProviderInfo;
}
+ /**
+ * Gets the extras Bundle.
+ *
+ * @return Returns a Bundle object.
+ */
+ @NonNull
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
@Override
public boolean equals(Object obj) {
if (!(obj instanceof KnownNetwork)) return false;
@@ -249,6 +276,7 @@ public final class KnownNetwork implements Parcelable {
dest.writeString(mSsid);
dest.writeArraySet(mSecurityTypes);
mNetworkProviderInfo.writeToParcel(dest, flags);
+ dest.writeBundle(mExtras);
}
/**
@@ -260,7 +288,7 @@ public final class KnownNetwork implements Parcelable {
public static KnownNetwork readFromParcel(@NonNull Parcel in) {
return new KnownNetwork(in.readInt(), in.readString(),
(ArraySet<Integer>) in.readArraySet(null),
- NetworkProviderInfo.readFromParcel(in));
+ NetworkProviderInfo.readFromParcel(in), in.readBundle());
}
@NonNull
@@ -283,6 +311,7 @@ public final class KnownNetwork implements Parcelable {
.append(", ssid=").append(mSsid)
.append(", securityTypes=").append(mSecurityTypes.toString())
.append(", networkProviderInfo=").append(mNetworkProviderInfo.toString())
+ .append(", extras=").append(mExtras.toString())
.append("]").toString();
}
}
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java
index 6bd0a5ecd4c8..b30dc3f6b530 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java
@@ -72,7 +72,7 @@ public final class KnownNetworkConnectionStatus implements Parcelable {
public static final class Builder {
@ConnectionStatus private int mStatus;
private KnownNetwork mKnownNetwork;
- private Bundle mExtras;
+ private Bundle mExtras = Bundle.EMPTY;
public Builder() {}
@@ -128,7 +128,7 @@ public final class KnownNetworkConnectionStatus implements Parcelable {
}
private KnownNetworkConnectionStatus(@ConnectionStatus int status, KnownNetwork knownNetwork,
- Bundle extras) {
+ @NonNull Bundle extras) {
validate(status);
mStatus = status;
mKnownNetwork = knownNetwork;
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
index ed4d699ad4de..25fbabce71ae 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
@@ -21,6 +21,7 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.net.wifi.sharedconnectivity.service.SharedConnectivityService;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -89,6 +90,7 @@ public final class NetworkProviderInfo implements Parcelable {
private final String mModelName;
private final int mBatteryPercentage;
private final int mConnectionStrength;
+ private final Bundle mExtras;
/**
* Builder class for {@link NetworkProviderInfo}.
@@ -99,6 +101,7 @@ public final class NetworkProviderInfo implements Parcelable {
private String mModelName;
private int mBatteryPercentage;
private int mConnectionStrength;
+ private Bundle mExtras = Bundle.EMPTY;
public Builder(@NonNull String deviceName, @NonNull String modelName) {
Objects.requireNonNull(deviceName);
@@ -170,6 +173,17 @@ public final class NetworkProviderInfo implements Parcelable {
}
/**
+ * Sets the extras bundle
+ *
+ * @return Returns the Builder object.
+ */
+ @NonNull
+ public Builder setExtras(@NonNull Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
* Builds the {@link NetworkProviderInfo} object.
*
* @return Returns the built {@link NetworkProviderInfo} object.
@@ -177,7 +191,7 @@ public final class NetworkProviderInfo implements Parcelable {
@NonNull
public NetworkProviderInfo build() {
return new NetworkProviderInfo(mDeviceType, mDeviceName, mModelName, mBatteryPercentage,
- mConnectionStrength);
+ mConnectionStrength, mExtras);
}
}
@@ -197,13 +211,15 @@ public final class NetworkProviderInfo implements Parcelable {
}
private NetworkProviderInfo(@DeviceType int deviceType, @NonNull String deviceName,
- @NonNull String modelName, int batteryPercentage, int connectionStrength) {
+ @NonNull String modelName, int batteryPercentage, int connectionStrength,
+ @NonNull Bundle extras) {
validate(deviceType, deviceName, modelName, batteryPercentage, connectionStrength);
mDeviceType = deviceType;
mDeviceName = deviceName;
mModelName = modelName;
mBatteryPercentage = batteryPercentage;
mConnectionStrength = connectionStrength;
+ mExtras = extras;
}
/**
@@ -256,6 +272,16 @@ public final class NetworkProviderInfo implements Parcelable {
return mConnectionStrength;
}
+ /**
+ * Gets the extras Bundle.
+ *
+ * @return Returns a Bundle object.
+ */
+ @NonNull
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
@Override
public boolean equals(Object obj) {
if (!(obj instanceof NetworkProviderInfo)) return false;
@@ -280,6 +306,7 @@ public final class NetworkProviderInfo implements Parcelable {
dest.writeString(mModelName);
dest.writeInt(mBatteryPercentage);
dest.writeInt(mConnectionStrength);
+ dest.writeBundle(mExtras);
}
@Override
@@ -295,7 +322,7 @@ public final class NetworkProviderInfo implements Parcelable {
@NonNull
public static NetworkProviderInfo readFromParcel(@NonNull Parcel in) {
return new NetworkProviderInfo(in.readInt(), in.readString(), in.readString(), in.readInt(),
- in.readInt());
+ in.readInt(), in.readBundle());
}
@NonNull
@@ -319,6 +346,7 @@ public final class NetworkProviderInfo implements Parcelable {
.append(", modelName=").append(mModelName)
.append(", batteryPercentage=").append(mBatteryPercentage)
.append(", connectionStrength=").append(mConnectionStrength)
+ .append(", extras=").append(mExtras.toString())
.append("]").toString();
}
}
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java
index 63e471b25ffb..30bb98962b3c 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivitySettingsState.java
@@ -51,7 +51,7 @@ public final class SharedConnectivitySettingsState implements Parcelable {
private boolean mInstantTetherEnabled;
private Intent mInstantTetherSettingsIntent;
private final Context mContext;
- private Bundle mExtras;
+ private Bundle mExtras = Bundle.EMPTY;
public Builder(@NonNull Context context) {
mContext = context;
@@ -112,8 +112,7 @@ public final class SharedConnectivitySettingsState implements Parcelable {
}
private SharedConnectivitySettingsState(boolean instantTetherEnabled,
- PendingIntent pendingIntent, Bundle extras) {
-
+ PendingIntent pendingIntent, @NonNull Bundle extras) {
mInstantTetherEnabled = instantTetherEnabled;
mInstantTetherSettingsPendingIntent = pendingIntent;
mExtras = extras;
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
index 8302094b1c34..0827ffaea482 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
@@ -28,6 +28,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import android.os.Bundle;
import android.os.Parcel;
import android.util.ArraySet;
@@ -55,6 +56,8 @@ public class HotspotNetworkTest {
private static final String HOTSPOT_SSID = "TEST_SSID";
private static final String HOTSPOT_BSSID = "TEST _BSSID";
private static final int[] HOTSPOT_SECURITY_TYPES = {SECURITY_TYPE_WEP, SECURITY_TYPE_EAP};
+ private static final String BUNDLE_KEY = "INT-KEY";
+ private static final int BUNDLE_VALUE = 1;
private static final long DEVICE_ID_1 = 111L;
private static final NetworkProviderInfo NETWORK_PROVIDER_INFO1 =
@@ -138,6 +141,7 @@ public class HotspotNetworkTest {
assertThat(network.getHotspotSsid()).isEqualTo(HOTSPOT_SSID);
assertThat(network.getHotspotBssid()).isEqualTo(HOTSPOT_BSSID);
assertThat(network.getHotspotSecurityTypes()).containsExactlyElementsIn(securityTypes);
+ assertThat(network.getExtras().getInt(BUNDLE_KEY)).isEqualTo(BUNDLE_VALUE);
}
@Test
@@ -161,11 +165,18 @@ public class HotspotNetworkTest {
.setHostNetworkType(NETWORK_TYPE)
.setNetworkName(NETWORK_NAME)
.setHotspotSsid(HOTSPOT_SSID)
- .setHotspotBssid(HOTSPOT_BSSID);
+ .setHotspotBssid(HOTSPOT_BSSID)
+ .setExtras(buildBundle());
Arrays.stream(HOTSPOT_SECURITY_TYPES).forEach(builder::addHotspotSecurityType);
if (withNetworkProviderInfo) {
builder.setNetworkProviderInfo(NETWORK_PROVIDER_INFO);
}
return builder;
}
+
+ private Bundle buildBundle() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(BUNDLE_KEY, BUNDLE_VALUE);
+ return bundle;
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java
index 1ecba7644cf9..81d7b44382e0 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java
@@ -25,6 +25,7 @@ import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE
import static com.google.common.truth.Truth.assertThat;
+import android.os.Bundle;
import android.os.Parcel;
import android.util.ArraySet;
@@ -47,6 +48,9 @@ public class KnownNetworkTest {
new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL")
.setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2)
.setBatteryPercentage(50).build();
+ private static final String BUNDLE_KEY = "INT-KEY";
+ private static final int BUNDLE_VALUE = 1;
+
private static final int NETWORK_SOURCE_1 = NETWORK_SOURCE_CLOUD_SELF;
private static final String SSID_1 = "TEST_SSID1";
private static final int[] SECURITY_TYPES_1 = {SECURITY_TYPE_PSK};
@@ -113,6 +117,7 @@ public class KnownNetworkTest {
assertThat(network.getSsid()).isEqualTo(SSID);
assertThat(network.getSecurityTypes()).containsExactlyElementsIn(securityTypes);
assertThat(network.getNetworkProviderInfo()).isEqualTo(NETWORK_PROVIDER_INFO);
+ assertThat(network.getExtras().getInt(BUNDLE_KEY)).isEqualTo(BUNDLE_VALUE);
}
@Test
@@ -125,8 +130,15 @@ public class KnownNetworkTest {
private KnownNetwork.Builder buildKnownNetworkBuilder() {
KnownNetwork.Builder builder = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE)
- .setSsid(SSID).setNetworkProviderInfo(NETWORK_PROVIDER_INFO);
+ .setSsid(SSID).setNetworkProviderInfo(NETWORK_PROVIDER_INFO)
+ .setExtras(buildBundle());
Arrays.stream(SECURITY_TYPES).forEach(builder::addSecurityType);
return builder;
}
+
+ private Bundle buildBundle() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(BUNDLE_KEY, BUNDLE_VALUE);
+ return bundle;
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java
index 8f35d8d94a8b..4aa9ca684ad0 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java
@@ -21,6 +21,7 @@ import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE
import static com.google.common.truth.Truth.assertThat;
+import android.os.Bundle;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
@@ -38,6 +39,8 @@ public class NetworkProviderInfoTest {
private static final String DEVICE_MODEL = "TEST_MODEL";
private static final int BATTERY_PERCENTAGE = 50;
private static final int CONNECTION_STRENGTH = 2;
+ private static final String BUNDLE_KEY = "INT-KEY";
+ private static final int BUNDLE_VALUE = 1;
private static final int DEVICE_TYPE_1 = DEVICE_TYPE_LAPTOP;
private static final String DEVICE_NAME_1 = "TEST_NAME1";
@@ -105,6 +108,7 @@ public class NetworkProviderInfoTest {
assertThat(info.getModelName()).isEqualTo(DEVICE_MODEL);
assertThat(info.getBatteryPercentage()).isEqualTo(BATTERY_PERCENTAGE);
assertThat(info.getConnectionStrength()).isEqualTo(CONNECTION_STRENGTH);
+ assertThat(info.getExtras().getInt(BUNDLE_KEY)).isEqualTo(BUNDLE_VALUE);
}
@Test
@@ -118,6 +122,13 @@ public class NetworkProviderInfoTest {
private NetworkProviderInfo.Builder buildNetworkProviderInfoBuilder() {
return new NetworkProviderInfo.Builder(DEVICE_NAME, DEVICE_MODEL).setDeviceType(DEVICE_TYPE)
.setBatteryPercentage(BATTERY_PERCENTAGE)
- .setConnectionStrength(CONNECTION_STRENGTH);
+ .setConnectionStrength(CONNECTION_STRENGTH)
+ .setExtras(buildBundle());
+ }
+
+ private Bundle buildBundle() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(BUNDLE_KEY, BUNDLE_VALUE);
+ return bundle;
}
}