summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java18
-rw-r--r--core/api/current.txt56
-rw-r--r--core/api/system-current.txt9
-rw-r--r--core/api/test-current.txt2
-rw-r--r--core/java/android/app/Dialog.java3
-rw-r--r--core/java/android/app/StatusBarManager.java40
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java40
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl6
-rw-r--r--core/java/android/app/usage/IUsageStatsManager.aidl2
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java12
-rw-r--r--core/java/android/content/pm/AppSearchShortcutInfo.java2
-rw-r--r--core/java/android/content/pm/Capability.aidl18
-rw-r--r--core/java/android/content/pm/Capability.java143
-rw-r--r--core/java/android/content/pm/CapabilityParams.aidl18
-rw-r--r--core/java/android/content/pm/CapabilityParams.java215
-rw-r--r--core/java/android/content/pm/PackageManager.java22
-rw-r--r--core/java/android/content/pm/ShortcutInfo.java131
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java13
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl6
-rw-r--r--core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl2
-rw-r--r--core/java/android/provider/Settings.java12
-rw-r--r--core/java/android/service/displayhash/DisplayHashingService.java3
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/java/android/window/OnBackInvokedCallback.java2
-rw-r--r--core/java/android/window/OnBackInvokedDispatcher.java6
-rw-r--r--core/java/android/window/ProxyOnBackInvokedDispatcher.java8
-rw-r--r--core/java/android/window/WindowOnBackInvokedDispatcher.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java50
-rw-r--r--core/java/com/android/server/SystemConfig.java37
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/tests/coretests/src/android/window/BackNavigationTest.java4
-rw-r--r--core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java23
-rw-r--r--data/etc/com.android.systemui.xml3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java11
-rw-r--r--media/java/android/media/MediaActionSound.java5
-rw-r--r--media/java/android/media/MediaCodec.java20
-rw-r--r--media/java/android/media/MediaFormat.java36
-rw-r--r--media/java/android/media/MediaRoute2Info.java2
-rw-r--r--media/java/android/media/RouteDiscoveryPreference.java5
-rw-r--r--media/java/android/media/tv/AdRequest.java6
-rw-r--r--media/java/android/media/tv/interactive/AppLinkInfo.aidl2
-rw-r--r--media/java/android/media/tv/interactive/AppLinkInfo.java2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl3
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl3
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl2
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppManager.java22
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppService.java29
-rw-r--r--media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl2
-rw-r--r--media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java2
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppView.java22
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java18
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java15
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java18
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java93
-rw-r--r--packages/SystemUI/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/res-keyguard/values/dimens.xml3
-rw-r--r--packages/SystemUI/res/drawable/media_ttt_undo_background.xml15
-rw-r--r--packages/SystemUI/res/drawable/user_switcher_icon_large.xml4
-rw-r--r--packages/SystemUI/res/values/config.xml14
-rw-r--r--packages/SystemUI/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt49
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt261
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java152
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt266
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java17
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java62
-rw-r--r--services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java83
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java16
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java27
-rw-r--r--services/core/java/com/android/server/am/AppBatteryExemptionTracker.java82
-rw-r--r--services/core/java/com/android/server/am/AppBatteryTracker.java68
-rw-r--r--services/core/java/com/android/server/am/AppRestrictionController.java7
-rw-r--r--services/core/java/com/android/server/am/BaseAppStateTracker.java4
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java16
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java18
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java14
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java17
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java22
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java22
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java5
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java4
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java17
-rw-r--r--services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java59
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java9
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java1
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java12
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java46
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java66
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java82
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java59
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java20
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java14
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java26
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl11
152 files changed, 2919 insertions, 1016 deletions
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index e2426c2f1758..f822a188c99c 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -2,6 +2,7 @@ package com.android.server.usage;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager.ProcessState;
import android.app.usage.AppStandbyInfo;
@@ -237,4 +238,11 @@ public interface AppStandbyInternal {
*/
@ProcessState
int getBroadcastResponseFgThresholdState();
+
+ /**
+ * Return the last known value corresponding to the {@code key} from
+ * {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController.
+ */
+ @Nullable
+ String getAppStandbyConstant(@NonNull String key);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 4952894c068b..1fdbecb22a37 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -100,6 +100,7 @@ import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings.Global;
import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -130,6 +131,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -375,6 +377,15 @@ public class AppStandbyController
ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE;
/**
+ * Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}.
+ *
+ * Note: We are intentionally not guarding this by any lock since this is only updated on
+ * a handler thread and when querying, if we do end up seeing slightly older values, it is fine
+ * since the values are only used in tests and doesn't need to be queried in any other cases.
+ */
+ private final Map<String, String> mAppStandbyProperties = new ArrayMap<>();
+
+ /**
* Whether we should allow apps into the
* {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not.
* If false, any attempts to put an app into the bucket will put the app into the
@@ -1837,6 +1848,12 @@ public class AppStandbyController
}
@Override
+ @Nullable
+ public String getAppStandbyConstant(@NonNull String key) {
+ return mAppStandbyProperties.get(key);
+ }
+
+ @Override
public void flushToDisk() {
synchronized (mAppIdleLock) {
mAppIdleHistory.writeAppIdleTimes(mInjector.elapsedRealtime());
@@ -2774,6 +2791,7 @@ public class AppStandbyController
}
break;
}
+ mAppStandbyProperties.put(name, properties.getString(name, null));
}
}
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 34b4acc361e1..0382c24dbf34 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7466,6 +7466,8 @@ package android.app.admin {
method public CharSequence getStartUserSessionMessage(@NonNull android.content.ComponentName);
method @Deprecated public boolean getStorageEncryption(@Nullable android.content.ComponentName);
method public int getStorageEncryptionStatus();
+ method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>);
+ method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>, @NonNull java.lang.Object...);
method @Nullable public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
method @Nullable public android.os.PersistableBundle getTransferOwnershipBundle();
method @Nullable public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(@Nullable android.content.ComponentName, @NonNull android.content.ComponentName);
@@ -11246,6 +11248,33 @@ package android.content.pm {
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Attribution> CREATOR;
}
+ public final class Capability implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public String getName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Capability> CREATOR;
+ }
+
+ public static final class Capability.Builder {
+ ctor public Capability.Builder(@NonNull String);
+ method @NonNull public android.content.pm.Capability build();
+ }
+
+ public final class CapabilityParams implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getAliases();
+ method @NonNull public String getName();
+ method @NonNull public String getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.CapabilityParams> CREATOR;
+ }
+
+ public static final class CapabilityParams.Builder {
+ ctor public CapabilityParams.Builder(@NonNull String, @NonNull String);
+ method @NonNull public android.content.pm.CapabilityParams.Builder addAlias(@NonNull String);
+ method @NonNull public android.content.pm.CapabilityParams build();
+ }
+
public final class ChangedPackages implements android.os.Parcelable {
ctor public ChangedPackages(int, @NonNull java.util.List<java.lang.String>);
method public int describeContents();
@@ -12307,7 +12336,8 @@ package android.content.pm {
method @NonNull public static android.content.pm.ShortcutInfo createFromGenericDocument(@NonNull android.content.Context, @NonNull android.app.appsearch.GenericDocument);
method public int describeContents();
method @Nullable public android.content.ComponentName getActivity();
- method @NonNull public java.util.List<java.lang.String> getCapabilityParameterValues(@NonNull String, @NonNull String);
+ method @NonNull public java.util.List<android.content.pm.Capability> getCapabilities();
+ method @NonNull public java.util.List<android.content.pm.CapabilityParams> getCapabilityParams(@NonNull android.content.pm.Capability);
method @Nullable public java.util.Set<java.lang.String> getCategories();
method @Nullable public CharSequence getDisabledMessage();
method public int getDisabledReason();
@@ -12322,7 +12352,6 @@ package android.content.pm {
method public int getRank();
method @Nullable public CharSequence getShortLabel();
method public android.os.UserHandle getUserHandle();
- method public boolean hasCapability(@NonNull String);
method public boolean hasKeyFieldsOnly();
method public boolean isCached();
method public boolean isDeclaredInManifest();
@@ -12347,7 +12376,7 @@ package android.content.pm {
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context, String);
- method @NonNull public android.content.pm.ShortcutInfo.Builder addCapabilityBinding(@NonNull String, @Nullable String, @Nullable java.util.List<java.lang.String>);
+ method @NonNull public android.content.pm.ShortcutInfo.Builder addCapabilityBinding(@NonNull android.content.pm.Capability, @Nullable android.content.pm.CapabilityParams);
method @NonNull public android.content.pm.ShortcutInfo build();
method @NonNull public android.content.pm.ShortcutInfo.Builder setActivity(@NonNull android.content.ComponentName);
method @NonNull public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
@@ -22211,6 +22240,10 @@ package android.media {
field public static final String KEY_COLOR_TRANSFER_REQUEST = "color-transfer-request";
field public static final String KEY_COMPLEXITY = "complexity";
field public static final String KEY_CREATE_INPUT_SURFACE_SUSPENDED = "create-input-buffers-suspended";
+ field public static final String KEY_CROP_BOTTOM = "crop-bottom";
+ field public static final String KEY_CROP_LEFT = "crop-left";
+ field public static final String KEY_CROP_RIGHT = "crop-right";
+ field public static final String KEY_CROP_TOP = "crop-top";
field public static final String KEY_DURATION = "durationUs";
field public static final String KEY_ENCODER_DELAY = "encoder-delay";
field public static final String KEY_ENCODER_PADDING = "encoder-padding";
@@ -22900,7 +22933,6 @@ package android.media {
method public int describeContents();
method @Nullable public String getClientPackageName();
method public int getConnectionState();
- method @NonNull public java.util.Set<java.lang.String> getDeduplicationIds();
method @Nullable public CharSequence getDescription();
method @Nullable public android.os.Bundle getExtras();
method @NonNull public java.util.List<java.lang.String> getFeatures();
@@ -22934,7 +22966,6 @@ package android.media {
method @NonNull public android.media.MediaRoute2Info.Builder clearFeatures();
method @NonNull public android.media.MediaRoute2Info.Builder setClientPackageName(@Nullable String);
method @NonNull public android.media.MediaRoute2Info.Builder setConnectionState(int);
- method @NonNull public android.media.MediaRoute2Info.Builder setDeduplicationIds(@NonNull java.util.Set<java.lang.String>);
method @NonNull public android.media.MediaRoute2Info.Builder setDescription(@Nullable CharSequence);
method @NonNull public android.media.MediaRoute2Info.Builder setExtras(@Nullable android.os.Bundle);
method @NonNull public android.media.MediaRoute2Info.Builder setIconUri(@Nullable android.net.Uri);
@@ -23461,11 +23492,8 @@ package android.media {
public final class RouteDiscoveryPreference implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public java.util.List<java.lang.String> getAllowedPackages();
- method @NonNull public java.util.List<java.lang.String> getDeduplicationPackageOrder();
method @NonNull public java.util.List<java.lang.String> getPreferredFeatures();
method public boolean shouldPerformActiveScan();
- method public boolean shouldRemoveDuplicates();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.RouteDiscoveryPreference> CREATOR;
}
@@ -23474,8 +23502,6 @@ package android.media {
ctor public RouteDiscoveryPreference.Builder(@NonNull java.util.List<java.lang.String>, boolean);
ctor public RouteDiscoveryPreference.Builder(@NonNull android.media.RouteDiscoveryPreference);
method @NonNull public android.media.RouteDiscoveryPreference build();
- method @NonNull public android.media.RouteDiscoveryPreference.Builder setAllowedPackages(@NonNull java.util.List<java.lang.String>);
- method @NonNull public android.media.RouteDiscoveryPreference.Builder setDeduplicationPackageOrder(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.media.RouteDiscoveryPreference.Builder setPreferredFeatures(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.media.RouteDiscoveryPreference.Builder setShouldPerformActiveScan(boolean);
}
@@ -26113,7 +26139,6 @@ package android.media.tv.interactive {
public final class TvInteractiveAppManager {
method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList();
- method public void prepare(@NonNull String, int);
method public void registerAppLinkInfo(@NonNull String, @NonNull android.media.tv.interactive.AppLinkInfo);
method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback);
method public void sendAppLinkCommand(@NonNull String, @NonNull android.os.Bundle);
@@ -26165,7 +26190,6 @@ package android.media.tv.interactive {
method public void onAppLinkCommand(@NonNull android.os.Bundle);
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method @Nullable public abstract android.media.tv.interactive.TvInteractiveAppService.Session onCreateSession(@NonNull String, int);
- method public abstract void onPrepare(int);
method public void onRegisterAppLinkInfo(@NonNull android.media.tv.interactive.AppLinkInfo);
method public void onUnregisterAppLinkInfo(@NonNull android.media.tv.interactive.AppLinkInfo);
field public static final String COMMAND_PARAMETER_KEY_CHANGE_CHANNEL_QUIETLY = "command_change_channel_quietly";
@@ -26195,12 +26219,12 @@ package android.media.tv.interactive {
method public void onBroadcastInfoResponse(@NonNull android.media.tv.BroadcastInfoResponse);
method public void onContentAllowed();
method public void onContentBlocked(@NonNull android.media.tv.TvContentRating);
- method public void onCreateBiInteractiveApp(@NonNull android.net.Uri, @Nullable android.os.Bundle);
+ method public void onCreateBiInteractiveAppRequest(@NonNull android.net.Uri, @Nullable android.os.Bundle);
method @Nullable public android.view.View onCreateMediaView();
method public void onCurrentChannelLcn(int);
method public void onCurrentChannelUri(@Nullable android.net.Uri);
method public void onCurrentTvInputId(@Nullable String);
- method public void onDestroyBiInteractiveApp(@NonNull String);
+ method public void onDestroyBiInteractiveAppRequest(@NonNull String);
method public boolean onGenericMotionEvent(@NonNull android.view.MotionEvent);
method public boolean onKeyDown(int, @NonNull android.view.KeyEvent);
method public boolean onKeyLongPress(int, @NonNull android.view.KeyEvent);
@@ -26285,6 +26309,8 @@ package android.media.tv.interactive {
method public void stopInteractiveApp();
field public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias";
field public static final String BI_INTERACTIVE_APP_KEY_CERTIFICATE = "certificate";
+ field public static final String BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS = "http_additional_headers";
+ field public static final String BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT = "http_user_agent";
field public static final String BI_INTERACTIVE_APP_KEY_PRIVATE_KEY = "private_key";
}
@@ -57937,7 +57963,7 @@ package android.window {
}
public interface OnBackInvokedDispatcher {
- method public void registerOnBackInvokedCallback(@NonNull android.window.OnBackInvokedCallback, @IntRange(from=0) int);
+ method public void registerOnBackInvokedCallback(@IntRange(from=0) int, @NonNull android.window.OnBackInvokedCallback);
method public void unregisterOnBackInvokedCallback(@NonNull android.window.OnBackInvokedCallback);
field public static final int PRIORITY_DEFAULT = 0; // 0x0
field public static final int PRIORITY_OVERLAY = 1000000; // 0xf4240
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index c7e820d00847..c8c94b5fca70 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -244,6 +244,7 @@ package android {
field public static final String READ_APP_SPECIFIC_LOCALES = "android.permission.READ_APP_SPECIFIC_LOCALES";
field public static final String READ_CARRIER_APP_INFO = "android.permission.READ_CARRIER_APP_INFO";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
+ field public static final String READ_CLIPBOARD_IN_BACKGROUND = "android.permission.READ_CLIPBOARD_IN_BACKGROUND";
field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
@@ -1090,8 +1091,6 @@ package android.app.admin {
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
- method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>);
- method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>, @NonNull java.lang.Object...);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public int getUserProvisioningState();
method public boolean isDeviceManaged();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
@@ -1104,8 +1103,8 @@ package android.app.admin {
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, android.Manifest.permission.PROVISION_DEMO_DEVICE}) public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetDrawables(@NonNull String[]);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetStrings(@NonNull String[]);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetDrawables(@NonNull java.util.Set<java.lang.String>);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetStrings(@NonNull java.util.Set<java.lang.String>);
method @RequiresPermission(android.Manifest.permission.SEND_LOST_MODE_LOCATION_UPDATES) public void sendLostModeLocationUpdate(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
@@ -3416,6 +3415,8 @@ package android.content.pm {
field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
+ field public static final String FEATURE_EROFS = "android.software.erofs";
+ field public static final String FEATURE_EROFS_LEGACY = "android.software.erofs_legacy";
field public static final String FEATURE_GAME_SERVICE = "android.software.game_service";
field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 6260f6b8a3ca..a67d002cdddf 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -512,7 +512,6 @@ package android.app.admin {
method public boolean isFactoryResetProtectionPolicySupported();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean isNewUserDisclaimerAcknowledged();
method public boolean isRemovingAdmin(@NonNull android.content.ComponentName, int);
- method @RequiresPermission(anyOf={android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName);
method @NonNull public static String operationSafetyReasonToString(int);
method @NonNull public static String operationToString(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void resetDefaultCrossProfileIntentFilters(int);
@@ -521,6 +520,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean setDeviceOwnerOnly(@NonNull android.content.ComponentName, @Nullable String, int);
method public void setDeviceOwnerType(@NonNull android.content.ComponentName, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public void setNextOperationSafety(int, int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}, conditional=true) public void setProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName, boolean);
field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
field public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED = "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED";
field public static final int DEVICE_OWNER_TYPE_DEFAULT = 0; // 0x0
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 82ff42b41799..a763b1464b6d 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -465,7 +465,8 @@ public class Dialog implements DialogInterface, Window.Callback,
onBackPressed();
}
};
- getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
+ getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mDefaultBackCallback);
mDefaultBackCallback = null;
}
}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 89854bbab3e8..ae0fc09e35a6 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -24,6 +24,9 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -39,6 +42,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Pair;
import android.util.Slog;
import android.view.View;
@@ -520,6 +524,27 @@ public class StatusBarManager {
private final Map<NearbyMediaDevicesProvider, NearbyMediaDevicesProviderWrapper>
nearbyMediaDevicesProviderMap = new HashMap<>();
+ /**
+ * Media controls based on {@link android.app.Notification.MediaStyle} notifications will have
+ * actions based on the media session's {@link android.media.session.PlaybackState}, rather than
+ * the notification's actions.
+ *
+ * These actions will be:
+ * - Play/Pause (depending on whether the current state is a playing state)
+ * - Previous (if declared), or a custom action if the slot is not reserved with
+ * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV}
+ * - Next (if declared), or a custom action if the slot is not reserved with
+ * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT}
+ * - Custom action
+ * - Custom action
+ *
+ * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
+ * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ private static final long MEDIA_CONTROL_SESSION_ACTIONS = 203800354L;
+
@UnsupportedAppUsage
private Context mContext;
private IStatusBarService mService;
@@ -1127,6 +1152,21 @@ public class StatusBarManager {
}
}
+ /**
+ * Checks whether the given package should use session-based actions for its media controls.
+ *
+ * @param packageName App posting media controls
+ * @param user Current user handle
+ * @return true if the app supports session actions
+ *
+ * @hide
+ */
+ @RequiresPermission(allOf = {android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ android.Manifest.permission.LOG_COMPAT_CHANGE})
+ public static boolean useMediaSessionActionsForApp(String packageName, UserHandle user) {
+ return CompatChanges.isChangeEnabled(MEDIA_CONTROL_SESSION_ACTIONS, packageName, user);
+ }
+
/** @hide */
public static String windowStateToString(int state) {
if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 47d29d91f155..223e5da5bc6d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -14073,12 +14073,12 @@ public class DevicePolicyManager {
/**
* Deprecated. Use {@code markProfileOwnerOnOrganizationOwnedDevice} instead.
* When called by an app targeting SDK level {@link android.os.Build.VERSION_CODES#Q} or
- * below, will behave the same as {@link #markProfileOwnerOnOrganizationOwnedDevice}.
+ * below, will behave the same as {@link #setProfileOwnerOnOrganizationOwnedDevice}.
*
* When called by an app targeting SDK level {@link android.os.Build.VERSION_CODES#R}
* or above, will throw an UnsupportedOperationException when called.
*
- * @deprecated Use {@link #markProfileOwnerOnOrganizationOwnedDevice} instead.
+ * @deprecated Use {@link #setProfileOwnerOnOrganizationOwnedDevice} instead.
*
* @hide
*/
@@ -14093,14 +14093,14 @@ public class DevicePolicyManager {
"This method is deprecated. use markProfileOwnerOnOrganizationOwnedDevice"
+ " instead.");
} else {
- markProfileOwnerOnOrganizationOwnedDevice(who);
+ setProfileOwnerOnOrganizationOwnedDevice(who, true);
}
}
/**
- * Marks the profile owner of the given user as managing an organization-owned device.
- * That will give it access to device identifiers (such as serial number, IMEI and MEID)
- * as well as other privileges.
+ * Sets whether the profile owner of the given user as managing an organization-owned device.
+ * Managing an organization-owned device will give it access to device identifiers (such as
+ * serial number, IMEI and MEID) as well as other privileges.
*
* @hide
*/
@@ -14108,13 +14108,15 @@ public class DevicePolicyManager {
@RequiresPermission(anyOf = {
android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED,
android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
- }, conditional = true)
- public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull ComponentName who) {
+ }, conditional = true)
+ public void setProfileOwnerOnOrganizationOwnedDevice(@NonNull ComponentName who,
+ boolean isProfileOwnerOnOrganizationOwnedDevice) {
if (mService == null) {
return;
}
try {
- mService.markProfileOwnerOnOrganizationOwnedDevice(who, myUserId());
+ mService.setProfileOwnerOnOrganizationOwnedDevice(who, myUserId(),
+ isProfileOwnerOnOrganizationOwnedDevice);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -15350,16 +15352,16 @@ public class DevicePolicyManager {
* <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
* registered receivers when a resource has been reset successfully.
*
- * @param drawableIds The list of IDs to remove.
+ * @param drawableIds The list of IDs to remove.
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
- public void resetDrawables(@NonNull String[] drawableIds) {
+ public void resetDrawables(@NonNull Set<String> drawableIds) {
if (mService != null) {
try {
- mService.resetDrawables(drawableIds);
+ mService.resetDrawables(new ArrayList<>(drawableIds));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -15659,10 +15661,10 @@ public class DevicePolicyManager {
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
- public void resetStrings(@NonNull String[] stringIds) {
+ public void resetStrings(@NonNull Set<String> stringIds) {
if (mService != null) {
try {
- mService.resetStrings(stringIds);
+ mService.resetStrings(new ArrayList<>(stringIds));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -15672,7 +15674,7 @@ public class DevicePolicyManager {
/**
* Returns the appropriate updated string for the {@code stringId} (see
* {@link DevicePolicyResources.Strings}) if one was set using
- * {@link #setStrings}, otherwise returns the string from {@code defaultStringLoader}.
+ * {@code setStrings}, otherwise returns the string from {@code defaultStringLoader}.
*
* <p>Also returns the string from {@code defaultStringLoader} if
* {@link DevicePolicyResources.Strings#UNDEFINED} was passed.
@@ -15684,15 +15686,12 @@ public class DevicePolicyManager {
* notified when a resource has been updated.
*
* <p>Note that each call to this API loads the resource from the package that called
- * {@link #setStrings} to set the updated resource.
+ * {@code setStrings} to set the updated resource.
*
* @param stringId The IDs to get the updated resource for.
* @param defaultStringLoader To get the default string if no updated string was set for
* {@code stringId}.
- *
- * @hide
*/
- @SystemApi
@Nullable
public String getString(
@NonNull @DevicePolicyResources.UpdatableStringId String stringId,
@@ -15735,10 +15734,7 @@ public class DevicePolicyManager {
* @param defaultStringLoader To get the default string if no updated string was set for
* {@code stringId}.
* @param formatArgs The format arguments that will be used for substitution.
- *
- * @hide
*/
- @SystemApi
@Nullable
@SuppressLint("SamShouldBeLast")
public String getString(
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 19bbdb1ec4c3..64241aa3312f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -477,7 +477,7 @@ interface IDevicePolicyManager {
int getGlobalPrivateDnsMode(in ComponentName admin);
String getGlobalPrivateDnsHost(in ComponentName admin);
- void markProfileOwnerOnOrganizationOwnedDevice(in ComponentName who, int userId);
+ void setProfileOwnerOnOrganizationOwnedDevice(in ComponentName who, int userId, boolean isProfileOwnerOnOrganizationOwnedDevice);
void installUpdateFromFile(in ComponentName admin, in ParcelFileDescriptor updateFileDescriptor, in StartInstallingUpdateCallback listener);
@@ -552,14 +552,14 @@ interface IDevicePolicyManager {
List<UserHandle> listForegroundAffiliatedUsers();
void setDrawables(in List<DevicePolicyDrawableResource> drawables);
- void resetDrawables(in String[] drawableIds);
+ void resetDrawables(in List<String> drawableIds);
ParcelableResource getDrawable(String drawableId, String drawableStyle, String drawableSource);
boolean isDpcDownloaded();
void setDpcDownloaded(boolean downloaded);
void setStrings(in List<DevicePolicyStringResource> strings);
- void resetStrings(in String[] stringIds);
+ void resetStrings(in List<String> stringIds);
ParcelableResource getString(String stringId);
boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 2a2a9c6e703e..7e142221b15d 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -82,4 +82,6 @@ interface IUsageStatsManager {
int userId);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
void clearBroadcastEvents(String callingPackage, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG)")
+ String getAppStandbyConstant(String key);
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 3a335f9d151b..b88a51312cd1 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -16,6 +16,7 @@
package android.app.usage;
+import android.Manifest;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -1505,4 +1506,15 @@ public final class UsageStatsManager {
throw re.rethrowFromSystemServer();
}
}
+
+ /** @hide */
+ @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
+ @Nullable
+ public String getAppStandbyConstant(@NonNull String key) {
+ try {
+ return mService.getAppStandbyConstant(key);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index f20d1e62e8e7..1b84686bbfcf 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -349,7 +349,7 @@ public class AppSearchShortcutInfo extends GenericDocument {
.setDisabledReason(shortcutInfo.getDisabledReason())
.setPersons(shortcutInfo.getPersons())
.setLocusId(shortcutInfo.getLocusId())
- .setCapabilityBindings(shortcutInfo.getCapabilityBindings())
+ .setCapabilityBindings(shortcutInfo.getCapabilityBindingsInternal())
.setTtlMillis(SHORTCUT_TTL)
.build();
}
diff --git a/core/java/android/content/pm/Capability.aidl b/core/java/android/content/pm/Capability.aidl
new file mode 100644
index 000000000000..df3b1be1ce31
--- /dev/null
+++ b/core/java/android/content/pm/Capability.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2022 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.content.pm;
+
+parcelable Capability; \ No newline at end of file
diff --git a/core/java/android/content/pm/Capability.java b/core/java/android/content/pm/Capability.java
new file mode 100644
index 000000000000..1597d31828a1
--- /dev/null
+++ b/core/java/android/content/pm/Capability.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2022 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.content.pm;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Represents a capability that can be performed by an app, also known as App Action.
+ * Capabilities can be associated with a {@link ShortcutInfo}.
+ *
+ * @see ShortcutInfo.Builder#addCapabilityBinding(Capability, CapabilityParams)
+ */
+public final class Capability implements Parcelable {
+
+ @NonNull
+ private final String mName;
+
+ /**
+ * Constructor.
+ * @param name Name of the capability, usually maps to a built-in intent,
+ * e.g. actions.intent.GET_MESSAGE. Note the character "/" is not permitted.
+ * @throws IllegalArgumentException If specified capability name contains the character "/".
+ *
+ * @hide
+ */
+ Capability(@NonNull final String name) {
+ Objects.requireNonNull(name);
+ if (name.contains("/")) {
+ throw new IllegalArgumentException("'/' is not permitted in the capability name");
+ }
+ mName = name;
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @hide
+ */
+ Capability(@NonNull final Capability orig) {
+ this(orig.mName);
+ }
+
+ private Capability(@NonNull final Builder builder) {
+ this(builder.mName);
+ }
+
+ private Capability(@NonNull final Parcel in) {
+ mName = in.readString();
+ }
+
+ /**
+ * Returns the name of the capability. e.g. actions.intent.GET_MESSAGE.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Capability)) {
+ return false;
+ }
+ return mName.equals(((Capability) obj).mName);
+ }
+
+ @Override
+ public int hashCode() {
+ return mName.hashCode();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mName);
+ }
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<Capability> CREATOR =
+ new Parcelable.Creator<Capability>() {
+ @Override
+ public Capability[] newArray(int size) {
+ return new Capability[size];
+ }
+
+ @Override
+ public Capability createFromParcel(@NonNull Parcel in) {
+ return new Capability(in);
+ }
+ };
+
+ /**
+ * Builder class for {@link Capability}.
+ */
+ public static final class Builder {
+
+ @NonNull
+ private final String mName;
+
+ /**
+ * Constructor.
+ * @param name Name of the capability, usually maps to a built-in intent,
+ * e.g. actions.intent.GET_MESSAGE. Note the character "/" is not permitted.
+ * @throws IllegalArgumentException If specified capability name contains the character "/".
+ */
+ public Builder(@NonNull final String name) {
+ Objects.requireNonNull(name);
+ if (name.contains("/")) {
+ throw new IllegalArgumentException("'/' is not permitted in the capability name");
+ }
+ mName = name;
+ }
+
+ /**
+ * Creates an instance of {@link Capability}
+ */
+ @NonNull
+ public Capability build() {
+ return new Capability(this);
+ }
+ }
+}
diff --git a/core/java/android/content/pm/CapabilityParams.aidl b/core/java/android/content/pm/CapabilityParams.aidl
new file mode 100644
index 000000000000..39f12387404f
--- /dev/null
+++ b/core/java/android/content/pm/CapabilityParams.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2022 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.content.pm;
+
+parcelable CapabilityParams;
diff --git a/core/java/android/content/pm/CapabilityParams.java b/core/java/android/content/pm/CapabilityParams.java
new file mode 100644
index 000000000000..7239bacf1221
--- /dev/null
+++ b/core/java/android/content/pm/CapabilityParams.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2022 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.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Represents the parameters and its matching names which can be associated with a
+ * {@link Capability}.
+ *
+ * @see ShortcutInfo.Builder#addCapabilityBinding(Capability, CapabilityParams)
+ */
+public final class CapabilityParams implements Parcelable {
+
+ @NonNull
+ private final String mName;
+ @NonNull
+ private final String mPrimaryValue;
+ @NonNull
+ private final List<String> mAliases;
+
+ /**
+ * Constructor.
+ * @param name Name of the capability parameter.
+ * Note the character "/" is not permitted.
+ * @param primaryValue The primary value of the parameter.
+ * @param aliases Alternative values of the parameter.
+ */
+ private CapabilityParams(@NonNull final String name,
+ @NonNull final String primaryValue, @Nullable final Collection<String> aliases) {
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(primaryValue);
+ mName = name;
+ mPrimaryValue = primaryValue;
+ mAliases = aliases == null ? Collections.emptyList()
+ : Collections.unmodifiableList(new ArrayList<>(aliases));
+ }
+
+ /**
+ * Copy constructor.
+ * @hide
+ */
+ CapabilityParams(@NonNull final CapabilityParams orig) {
+ this(orig.mName, orig.mPrimaryValue, orig.mAliases);
+ }
+
+ private CapabilityParams(@NonNull final Builder builder) {
+ this(builder.mKey, builder.mPrimaryValue, builder.mAliases);
+ }
+
+ private CapabilityParams(@NonNull final Parcel in) {
+ mName = in.readString();
+ mPrimaryValue = in.readString();
+ final List<String> values = new ArrayList<>();
+ in.readStringList(values);
+ mAliases = Collections.unmodifiableList(values);
+ }
+
+ /**
+ * Name of the parameter.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Returns the primary name of values in this parameter.
+ */
+ @NonNull
+ public String getValue() {
+ return mPrimaryValue;
+ }
+
+ /**
+ * Returns the aliases of the values in ths parameter. Returns an empty list if there are no
+ * aliases.
+ */
+ @NonNull
+ public List<String> getAliases() {
+ return new ArrayList<>(mAliases);
+ }
+
+ /**
+ * A list of values for this parameter. The first value will be the primary name, while the
+ * rest will be alternative names.
+ * @hide
+ */
+ @NonNull
+ List<String> getValues() {
+ if (mAliases == null) {
+ return new ArrayList<>(Collections.singletonList(mPrimaryValue));
+ }
+ final List<String> ret = new ArrayList<>(mAliases.size() + 1);
+ ret.add(mPrimaryValue);
+ ret.addAll(mAliases);
+ return ret;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof CapabilityParams)) {
+ return false;
+ }
+ final CapabilityParams target = (CapabilityParams) obj;
+ return mName.equals(target.mName) && mPrimaryValue.equals(target.mPrimaryValue)
+ && mAliases.equals(target.mAliases);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mPrimaryValue, mAliases);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mName);
+ dest.writeString(mPrimaryValue);
+ dest.writeStringList(mAliases);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<CapabilityParams> CREATOR =
+ new Parcelable.Creator<CapabilityParams>() {
+ @Override
+ public CapabilityParams[] newArray(int size) {
+ return new CapabilityParams[size];
+ }
+
+ @Override
+ public CapabilityParams createFromParcel(@NonNull Parcel in) {
+ return new CapabilityParams(in);
+ }
+ };
+
+ /**
+ * Builder class for {@link CapabilityParams}.
+ */
+ public static final class Builder {
+
+ @NonNull
+ private final String mKey;
+ @NonNull
+ private String mPrimaryValue;
+ @NonNull
+ private Set<String> mAliases;
+
+ /**
+ * Constructor.
+ * @param key key of the capability parameter.
+ * Note the character "/" is not permitted.
+ * @param value The primary name of value in the {@link CapabilityParams}, cannot be empty.
+ */
+ public Builder(@NonNull final String key, @NonNull final String value) {
+ Objects.requireNonNull(key);
+ if (TextUtils.isEmpty(value)) {
+ throw new IllegalArgumentException("Primary value cannot be empty or null");
+ }
+ mPrimaryValue = value;
+ mKey = key;
+ }
+
+ /**
+ * Add an alias in the {@link CapabilityParams}.
+ */
+ @NonNull
+ public Builder addAlias(@NonNull final String alias) {
+ if (mAliases == null) {
+ mAliases = new ArraySet<>(1);
+ }
+ mAliases.add(alias);
+ return this;
+ }
+
+ /**
+ * Creates an instance of {@link CapabilityParams}
+ * @throws IllegalArgumentException If the specified value is empty.
+ */
+ @NonNull
+ public CapabilityParams build() {
+ return new CapabilityParams(this);
+ }
+ }
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 81c941eedef0..c91ee1395687 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4087,6 +4087,28 @@ public abstract class PackageManager {
"android.software.incremental_delivery";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * has the requisite kernel support for the EROFS filesystem present in 4.19 kernels as a
+ * staging driver, which lacks 0padding and big pcluster support.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_EROFS_LEGACY = "android.software.erofs_legacy";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * has the requisite kernel support for the EROFS filesystem present in 5.10 kernels, which
+ * has 0padding, big pcluster, and chunked index support.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_EROFS = "android.software.erofs";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device has tuner hardware to support tuner operations.
*
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 41dd5bb3f21d..56d092d8319d 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -52,7 +52,7 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Collection;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -60,7 +60,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
* Represents a shortcut that can be published via {@link ShortcutManager}.
@@ -501,7 +500,8 @@ public final class ShortcutInfo implements Parcelable {
mRank = b.mRank;
mExtras = b.mExtras;
mLocusId = b.mLocusId;
- mCapabilityBindings = b.mCapabilityBindings;
+ mCapabilityBindings =
+ cloneCapabilityBindings(b.mCapabilityBindings);
mStartingThemeResName = b.mStartingThemeResId != 0
? b.mContext.getResources().getResourceName(b.mStartingThemeResId) : null;
updateTimestamp();
@@ -652,7 +652,8 @@ public final class ShortcutInfo implements Parcelable {
// Set this bit.
mFlags |= FLAG_KEY_FIELDS_ONLY;
}
- mCapabilityBindings = source.mCapabilityBindings;
+ mCapabilityBindings = cloneCapabilityBindings(
+ source.mCapabilityBindings);
mStartingThemeResName = source.mStartingThemeResName;
}
@@ -1003,7 +1004,8 @@ public final class ShortcutInfo implements Parcelable {
mStartingThemeResName = source.mStartingThemeResName;
}
if (source.mCapabilityBindings != null) {
- mCapabilityBindings = source.mCapabilityBindings;
+ mCapabilityBindings =
+ cloneCapabilityBindings(source.mCapabilityBindings);
}
}
@@ -1447,43 +1449,25 @@ public final class ShortcutInfo implements Parcelable {
* <P>This method can be called multiple times to add multiple parameters to the same
* capability.
*
- * @param capability capability associated with the shortcut. e.g. actions.intent
- * .START_EXERCISE.
- * @param parameterName name of the parameter associated with given capability.
- * e.g. exercise.name.
- * @param parameterValues a list of values for that parameters. The first value will be
- * the primary name, while the rest will be alternative names. If
- * the values are empty, then the parameter will not be saved in
- * the shortcut.
+ * @param capability {@link Capability} associated with the shortcut.
+ * @param capabilityParams Optional {@link CapabilityParams} associated with given
+ * capability.
*/
@NonNull
- public Builder addCapabilityBinding(@NonNull String capability,
- @Nullable String parameterName, @Nullable List<String> parameterValues) {
+ public Builder addCapabilityBinding(@NonNull final Capability capability,
+ @Nullable final CapabilityParams capabilityParams) {
Objects.requireNonNull(capability);
- if (capability.contains("/")) {
- throw new IllegalArgumentException("Illegal character '/' is found in capability");
- }
if (mCapabilityBindings == null) {
mCapabilityBindings = new ArrayMap<>(1);
}
- if (!mCapabilityBindings.containsKey(capability)) {
- mCapabilityBindings.put(capability, new ArrayMap<>(0));
- }
- if (parameterName == null || parameterValues == null || parameterValues.isEmpty()) {
- return this;
- }
- if (parameterName.contains("/")) {
- throw new IllegalArgumentException(
- "Illegal character '/' is found in parameter name");
+ if (!mCapabilityBindings.containsKey(capability.getName())) {
+ mCapabilityBindings.put(capability.getName(), new ArrayMap<>(0));
}
- final Map<String, List<String>> params = mCapabilityBindings.get(capability);
- if (!params.containsKey(parameterName)) {
- params.put(parameterName, parameterValues);
+ if (capabilityParams == null) {
return this;
}
- params.put(parameterName,
- Stream.of(params.get(parameterName), parameterValues)
- .flatMap(Collection::stream).collect(Collectors.toList()));
+ final Map<String, List<String>> params = mCapabilityBindings.get(capability.getName());
+ params.put(capabilityParams.getName(), capabilityParams.getValues());
return this;
}
@@ -2264,41 +2248,78 @@ public final class ShortcutInfo implements Parcelable {
}
/**
+ * Returns an immutable copy of the capability bindings using internal data structure.
* @hide
*/
- public Map<String, Map<String, List<String>>> getCapabilityBindings() {
- return mCapabilityBindings;
+ @Nullable
+ public Map<String, Map<String, List<String>>> getCapabilityBindingsInternal() {
+ return cloneCapabilityBindings(mCapabilityBindings);
+ }
+
+ @Nullable
+ private static Map<String, Map<String, List<String>>> cloneCapabilityBindings(
+ @Nullable final Map<String, Map<String, List<String>>> orig) {
+ if (orig == null) {
+ return null;
+ }
+ final Map<String, Map<String, List<String>>> ret = new ArrayMap<>();
+ for (String capability : orig.keySet()) {
+ final Map<String, List<String>> params = orig.get(capability);
+ final Map<String, List<String>> clone;
+ if (params == null) {
+ clone = null;
+ } else {
+ clone = new ArrayMap<>(params.size());
+ for (String paramName : params.keySet()) {
+ final List<String> paramValues = params.get(paramName);
+ clone.put(paramName, Collections.unmodifiableList(paramValues));
+ }
+ }
+ ret.put(capability, Collections.unmodifiableMap(clone));
+ }
+ return Collections.unmodifiableMap(ret);
}
/**
- * Return true if the shortcut is or can be used in specified capability.
+ * Return a list of {@link Capability} associated with the shortcut.
*/
- public boolean hasCapability(@NonNull String capability) {
- Objects.requireNonNull(capability);
- return mCapabilityBindings != null && mCapabilityBindings.containsKey(capability);
+ @NonNull
+ public List<Capability> getCapabilities() {
+ if (mCapabilityBindings == null) {
+ return new ArrayList<>(0);
+ }
+ return mCapabilityBindings.keySet().stream().map(Capability::new)
+ .collect(Collectors.toList());
}
/**
- * Returns the values of specified parameter in associated with given capability.
+ * Returns the {@link CapabilityParams} in associated with given capability.
*
- * @param capability capability associated with the shortcut. e.g. actions.intent
- * .START_EXERCISE.
- * @param parameterName name of the parameter associated with given capability.
- * e.g. exercise.name.
+ * @param capability {@link Capability} associated with the shortcut.
*/
@NonNull
- public List<String> getCapabilityParameterValues(
- @NonNull String capability, @NonNull String parameterName) {
+ public List<CapabilityParams> getCapabilityParams(@NonNull final Capability capability) {
Objects.requireNonNull(capability);
- Objects.requireNonNull(parameterName);
if (mCapabilityBindings == null) {
- return Collections.emptyList();
- }
- final Map<String, List<String>> param = mCapabilityBindings.get(capability);
- if (param == null || !param.containsKey(parameterName)) {
- return Collections.emptyList();
+ return new ArrayList<>(0);
+ }
+ final Map<String, List<String>> param = mCapabilityBindings.get(capability.getName());
+ if (param == null) {
+ return new ArrayList<>(0);
+ }
+ final List<CapabilityParams> ret = new ArrayList<>(param.size());
+ for (String key : param.keySet()) {
+ final List<String> values = param.get(key);
+ final String primaryValue = values.get(0);
+ final List<String> aliases = values.size() == 1
+ ? Collections.emptyList() : values.subList(1, values.size());
+ CapabilityParams.Builder builder = new CapabilityParams.Builder(key, primaryValue);
+ for (String alias : aliases) {
+ builder = builder.addAlias(alias);
+ }
+ ret.add(builder.build());
}
- return param.get(parameterName);
+ return ret;
}
private ShortcutInfo(Parcel source) {
@@ -2357,7 +2378,7 @@ public final class ShortcutInfo implements Parcelable {
final Map<String, Map<String, List<String>>> capabilityBindings =
new ArrayMap<>(rawCapabilityBindings.size());
rawCapabilityBindings.forEach(capabilityBindings::put);
- mCapabilityBindings = capabilityBindings;
+ mCapabilityBindings = cloneCapabilityBindings(capabilityBindings);
}
}
@@ -2695,6 +2716,6 @@ public final class ShortcutInfo implements Parcelable {
mPersons = persons;
mLocusId = locusId;
mStartingThemeResName = startingThemeResName;
- mCapabilityBindings = capabilityBindings;
+ mCapabilityBindings = cloneCapabilityBindings(capabilityBindings);
}
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7e070bc06056..29221b801ef6 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -923,14 +923,15 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
if (mService == null) {
Slog.w(TAG, "onFingerDown: no fingerprint service");
return;
}
try {
- mService.onPointerDown(sensorId, x, y, minor, major);
+ mService.onPointerDown(requestId, sensorId, x, y, minor, major);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -940,14 +941,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
if (mService == null) {
Slog.w(TAG, "onFingerDown: no fingerprint service");
return;
}
try {
- mService.onPointerUp(sensorId);
+ mService.onPointerUp(requestId, sensorId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -957,14 +958,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onUiReady(int sensorId) {
+ public void onUiReady(long requestId, int sensorId) {
if (mService == null) {
Slog.w(TAG, "onUiReady: no fingerprint service");
return;
}
try {
- mService.onUiReady(sensorId);
+ mService.onUiReady(requestId, sensorId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index cbff8b11a72a..12114aa3fa33 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -155,13 +155,13 @@ interface IFingerprintService {
void addAuthenticatorsRegisteredCallback(IFingerprintAuthenticatorsRegisteredCallback callback);
// Notifies about a finger touching the sensor area.
- void onPointerDown(int sensorId, int x, int y, float minor, float major);
+ void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major);
// Notifies about a finger leaving the sensor area.
- void onPointerUp(int sensorId);
+ void onPointerUp(long requestId, int sensorId);
// Notifies about the fingerprint UI being ready (e.g. HBM illumination is enabled).
- void onUiReady(int sensorId);
+ void onUiReady(long requestId, int sensorId);
// Sets the controller for managing the UDFPS overlay.
void setUdfpsOverlayController(in IUdfpsOverlayController controller);
diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
index 3cca1b38e5e2..dbb8e40f3a71 100644
--- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
+++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
@@ -23,7 +23,7 @@ import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
*/
oneway interface IUdfpsOverlayController {
// Shows the overlay for the given sensor with a reason from BiometricOverlayConstants.
- void showUdfpsOverlay(int sensorId, int reason, IUdfpsOverlayControllerCallback callback);
+ void showUdfpsOverlay(long requestId, int sensorId, int reason, IUdfpsOverlayControllerCallback callback);
// Hides the overlay.
void hideUdfpsOverlay(int sensorId);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a6ad5e5863df..5191c9583379 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2143,10 +2143,10 @@ public final class Settings {
/**
* Intent extra: The id of a setting restricted by supervisors.
* <p>
- * Type: Integer with a value from the SupervisorVerificationSetting annotation below.
+ * Type: Integer with a value from the one of the SUPERVISOR_VERIFICATION_* constants below.
* <ul>
- * <li>{@link #SUPERVISOR_VERIFICATION_SETTING_UNKNOWN}
- * <li>{@link #SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS}
+ * <li>{@see #SUPERVISOR_VERIFICATION_SETTING_UNKNOWN}
+ * <li>{@see #SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS}
* </ul>
* </p>
*/
@@ -2154,12 +2154,14 @@ public final class Settings {
"android.provider.extra.SUPERVISOR_RESTRICTED_SETTING_KEY";
/**
- * Unknown setting.
+ * The unknown setting can usually be ignored and is used for compatibility with future
+ * supervisor settings.
*/
public static final int SUPERVISOR_VERIFICATION_SETTING_UNKNOWN = 0;
/**
- * Biometric settings for supervisors.
+ * Settings for supervisors to control what kinds of biometric sensors, such a face and
+ * fingerprint scanners, can be used on the device.
*/
public static final int SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS = 1;
diff --git a/core/java/android/service/displayhash/DisplayHashingService.java b/core/java/android/service/displayhash/DisplayHashingService.java
index f22d40ea4d5e..3fac23b61a4b 100644
--- a/core/java/android/service/displayhash/DisplayHashingService.java
+++ b/core/java/android/service/displayhash/DisplayHashingService.java
@@ -68,9 +68,6 @@ public abstract class DisplayHashingService extends Service {
private DisplayHashingServiceWrapper mWrapper;
private Handler mHandler;
- public DisplayHashingService() {
- }
-
@Override
public void onCreate() {
super.onCreate();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b72725ad2c32..3879ce0b5ce6 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -10923,7 +10923,7 @@ public final class ViewRootImpl implements ViewParent,
}
};
mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
- mCompatOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatOnBackInvokedCallback);
}
private void unregisterCompatOnBackInvokedCallback() {
diff --git a/core/java/android/window/OnBackInvokedCallback.java b/core/java/android/window/OnBackInvokedCallback.java
index dcd80fd76e09..400a56f2c485 100644
--- a/core/java/android/window/OnBackInvokedCallback.java
+++ b/core/java/android/window/OnBackInvokedCallback.java
@@ -33,7 +33,7 @@ import android.view.View;
* within the same priority. Between different pirorities, callbacks with higher priority
* are invoked first.
*
- * See {@link OnBackInvokedDispatcher#registerOnBackInvokedCallback(OnBackInvokedCallback, int)}
+ * See {@link OnBackInvokedDispatcher#registerOnBackInvokedCallback(int, OnBackInvokedCallback)}
* for specifying callback priority.
*/
public interface OnBackInvokedCallback {
diff --git a/core/java/android/window/OnBackInvokedDispatcher.java b/core/java/android/window/OnBackInvokedDispatcher.java
index 63e6d30c8c0b..5eed8cde8c7c 100644
--- a/core/java/android/window/OnBackInvokedDispatcher.java
+++ b/core/java/android/window/OnBackInvokedDispatcher.java
@@ -94,15 +94,15 @@ public interface OnBackInvokedDispatcher {
* Within the same priority level, callbacks are invoked in the reverse order in which
* they are registered. Higher priority callbacks are invoked before lower priority ones.
*
+ * @param priority The priority of the callback.
* @param callback The callback to be registered. If the callback instance has been already
* registered, the existing instance (no matter its priority) will be
* unregistered and registered again.
- * @param priority The priority of the callback.
* @throws {@link IllegalArgumentException} if the priority is negative.
*/
- @SuppressLint({"SamShouldBeLast", "ExecutorRegistration"})
+ @SuppressLint({"ExecutorRegistration"})
void registerOnBackInvokedCallback(
- @NonNull OnBackInvokedCallback callback, @Priority @IntRange(from = 0) int priority);
+ @Priority @IntRange(from = 0) int priority, @NonNull OnBackInvokedCallback callback);
/**
* Unregisters a {@link OnBackInvokedCallback}.
diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
index cf17a2116aac..2b2f5e945710 100644
--- a/core/java/android/window/ProxyOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
@@ -44,7 +44,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
/**
* List of pair representing an {@link OnBackInvokedCallback} and its associated priority.
*
- * @see OnBackInvokedDispatcher#registerOnBackInvokedCallback(OnBackInvokedCallback, int)
+ * @see OnBackInvokedDispatcher#registerOnBackInvokedCallback(int, OnBackInvokedCallback)
*/
private final List<Pair<OnBackInvokedCallback, Integer>> mCallbacks = new ArrayList<>();
private final Object mLock = new Object();
@@ -52,7 +52,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
@Override
public void registerOnBackInvokedCallback(
- @NonNull OnBackInvokedCallback callback, int priority) {
+ int priority, @NonNull OnBackInvokedCallback callback) {
if (DEBUG) {
Log.v(TAG, String.format("Pending register %s. Actual=%s", callback,
mActualDispatcherOwner));
@@ -91,7 +91,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
mCallbacks.add(Pair.create(callback, priority));
if (mActualDispatcherOwner != null) {
mActualDispatcherOwner.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
- callback, priority);
+ priority, callback);
}
}
}
@@ -115,7 +115,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
for (Pair<OnBackInvokedCallback, Integer> callbackPair : mCallbacks) {
int priority = callbackPair.second;
if (priority >= 0) {
- dispatcher.registerOnBackInvokedCallback(callbackPair.first, priority);
+ dispatcher.registerOnBackInvokedCallback(priority, callbackPair.first);
} else {
dispatcher.registerSystemOnBackInvokedCallback(callbackPair.first);
}
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index d046cefee5f7..97573c291340 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -83,7 +83,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
// TODO: Take an Executor for the callback to run on.
@Override
public void registerOnBackInvokedCallback(
- @NonNull OnBackInvokedCallback callback, @Priority int priority) {
+ @Priority int priority, @NonNull OnBackInvokedCallback callback) {
if (priority < 0) {
throw new IllegalArgumentException("Application registered OnBackInvokedCallback "
+ "cannot have negative priority. Priority: " + priority);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 3b46f627265b..8901c0774783 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4763,8 +4763,11 @@ public class BatteryStatsImpl extends BatteryStats {
if (Process.isSdkSandboxUid(uid)) {
return Process.getAppUidForSdkSandboxUid(uid);
}
- int isolated = mIsolatedUids.get(uid, -1);
- return isolated > 0 ? isolated : uid;
+ return mapIsolatedUid(uid);
+ }
+
+ private int mapIsolatedUid(int uid) {
+ return mIsolatedUids.get(/*key=*/uid, /*valueIfKeyNotFound=*/uid);
}
@GuardedBy("this")
@@ -5215,7 +5218,7 @@ public class BatteryStatsImpl extends BatteryStats {
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
} else {
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
- mappedUid, null, getPowerManagerWakeLockLevel(type), name,
+ mapIsolatedUid(uid), null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
}
}
@@ -5269,7 +5272,7 @@ public class BatteryStatsImpl extends BatteryStats {
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
} else {
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
- mappedUid, null, getPowerManagerWakeLockLevel(type), name,
+ mapIsolatedUid(uid), null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
}
@@ -5693,7 +5696,10 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
private void noteStartGpsLocked(int uid, WorkChain workChain,
long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ final int mappedUid = mapUid(uid);
if (mGpsNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
@@ -5703,21 +5709,24 @@ public class BatteryStatsImpl extends BatteryStats {
mGpsNesting++;
if (workChain == null) {
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, uid, null,
- FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
+ mapIsolatedUid(uid), null, FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
} else {
FrameworkStatsLog.write(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
workChain.getUids(), workChain.getTags(),
FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
}
- getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteStartGps(elapsedRealtimeMs);
+ getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs).noteStartGps(elapsedRealtimeMs);
}
@GuardedBy("this")
private void noteStopGpsLocked(int uid, WorkChain workChain,
long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ final int mappedUid = mapUid(uid);
mGpsNesting--;
if (mGpsNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
@@ -5729,14 +5738,15 @@ public class BatteryStatsImpl extends BatteryStats {
}
if (workChain == null) {
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, uid, null,
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
+ mapIsolatedUid(uid), null,
FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF);
} else {
FrameworkStatsLog.write(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, workChain.getUids(),
workChain.getTags(), FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF);
}
- getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteStopGps(elapsedRealtimeMs);
+ getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs).noteStopGps(elapsedRealtimeMs);
}
@GuardedBy("this")
@@ -7154,7 +7164,10 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
private void noteBluetoothScanStartedLocked(WorkChain workChain, int uid,
boolean isUnoptimized, long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ uid = mapUid(uid);
if (mBluetoothScanNesting == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: "
@@ -7194,7 +7207,10 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
private void noteBluetoothScanStoppedLocked(WorkChain workChain, int uid,
boolean isUnoptimized, long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ uid = mapUid(uid);
mBluetoothScanNesting--;
if (mBluetoothScanNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
@@ -7207,14 +7223,6 @@ public class BatteryStatsImpl extends BatteryStats {
.noteBluetoothScanStoppedLocked(elapsedRealtimeMs, isUnoptimized);
}
- private int getAttributionUid(int uid, WorkChain workChain) {
- if (workChain != null) {
- return mapUid(workChain.getAttributionUid());
- }
-
- return mapUid(uid);
- }
-
@GuardedBy("this")
public void noteBluetoothScanStoppedFromSourceLocked(WorkSource ws, boolean isUnoptimized) {
noteBluetoothScanStoppedFromSourceLocked(ws, isUnoptimized,
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index e281853d31bf..db41d333e1d4 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -31,6 +31,7 @@ import android.os.FileUtils;
import android.os.Process;
import android.os.SystemProperties;
import android.os.Trace;
+import android.os.VintfRuntimeInfo;
import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.permission.PermissionManager.SplitPermissionInfo;
@@ -57,7 +58,10 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -1447,6 +1451,14 @@ public class SystemConfig {
addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
}
+ if (isFilesystemSupported("erofs")) {
+ if (isKernelVersionAtLeast(5, 10)) {
+ addFeature(PackageManager.FEATURE_EROFS, 0);
+ } else if (isKernelVersionAtLeast(4, 19)) {
+ addFeature(PackageManager.FEATURE_EROFS_LEGACY, 0);
+ }
+ }
+
for (String featureName : mUnavailableFeatures) {
removeFeature(featureName);
}
@@ -1816,4 +1828,29 @@ public class SystemConfig {
private static boolean isSystemProcess() {
return Process.myUid() == Process.SYSTEM_UID;
}
+
+ private static boolean isFilesystemSupported(String fs) {
+ try {
+ final byte[] fsTableData = Files.readAllBytes(Paths.get("/proc/filesystems"));
+ final String fsTable = new String(fsTableData, StandardCharsets.UTF_8);
+ return fsTable.contains("\t" + fs + "\n");
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ private static boolean isKernelVersionAtLeast(int major, int minor) {
+ final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
+ final String[] parts = kernelVersion.split("\\.");
+ if (parts.length < 2) {
+ return false;
+ }
+ try {
+ final int majorVersion = Integer.parseInt(parts[0]);
+ final int minorVersion = Integer.parseInt(parts[1]);
+ return majorVersion > major || (majorVersion == major && minorVersion >= minor);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5551e46531ed..0c194db02128 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -721,6 +721,7 @@
<!-- Added in T -->
<protected-broadcast android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES" />
+ <protected-broadcast android:name="android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED" />
<protected-broadcast android:name="android.app.action.DEVICE_POLICY_RESOURCE_UPDATED" />
<protected-broadcast android:name="android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER" />
<protected-broadcast android:name="android.service.autofill.action.DELAYED_FILL" />
@@ -6053,10 +6054,10 @@
<permission android:name="android.permission.MANAGE_APPOPS"
android:protectionLevel="signature" />
- <!-- @hide Permission that allows background clipboard access.
- <p>Not for use by third-party applications. -->
+ <!-- @SystemApi Permission that allows background clipboard access.
+ @hide Not for use by third-party applications. -->
<permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|role" />
<!-- @hide Permission that suppresses the notification when the clipboard is accessed.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION"
diff --git a/core/tests/coretests/src/android/window/BackNavigationTest.java b/core/tests/coretests/src/android/window/BackNavigationTest.java
index 8fa48ef5494d..94a149b09d54 100644
--- a/core/tests/coretests/src/android/window/BackNavigationTest.java
+++ b/core/tests/coretests/src/android/window/BackNavigationTest.java
@@ -111,12 +111,12 @@ public class BackNavigationTest {
CountDownLatch backRegisteredLatch = new CountDownLatch(1);
mScenario.onActivity(activity -> {
activity.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
- new OnBackInvokedCallback() {
+ 0, new OnBackInvokedCallback() {
@Override
public void onBackInvoked() {
backInvokedLatch.countDown();
}
- }, 0
+ }
);
backRegisteredLatch.countDown();
});
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index f8c994416f46..212f4ed92b8c 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -77,9 +77,9 @@ public class WindowOnBackInvokedDispatcherTest {
ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
verify(mWindowSession, times(2)).setOnBackInvokedCallback(
Mockito.eq(mWindow),
@@ -102,9 +102,9 @@ public class WindowOnBackInvokedDispatcherTest {
ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+ OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback1);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
verify(mWindowSession).setOnBackInvokedCallback(
Mockito.eq(mWindow), captor.capture(),
@@ -118,9 +118,9 @@ public class WindowOnBackInvokedDispatcherTest {
@Test
public void propagatesTopCallback_withRemoval() throws RemoteException {
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
reset(mWindowSession);
mDispatcher.unregisterOnBackInvokedCallback(mCallback1);
@@ -139,16 +139,17 @@ public class WindowOnBackInvokedDispatcherTest {
ArgumentCaptor<IOnBackInvokedCallback> captor =
ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
- mDispatcher.registerOnBackInvokedCallback(mCallback1,
- OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+ mDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_OVERLAY,
+ mCallback1
+ );
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
reset(mWindowSession);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+ OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback2);
verify(mWindowSession).setOnBackInvokedCallback(
Mockito.eq(mWindow),
captor.capture(),
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index d1873a0f40cf..2d1db716b700 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -76,5 +76,8 @@
<permission name="android.permission.FORCE_STOP_PACKAGES" />
<permission name="android.permission.ACCESS_FPS_COUNTER" />
<permission name="android.permission.CHANGE_CONFIGURATION" />
+ <permission name="android.permission.LOG_COMPAT_CHANGE" />
+ <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <permission name="android.permission.READ_DEVICE_CONFIG" />
</privapp-permissions>
</permissions>
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 58f79f3600de..13d12b3589c0 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
@@ -1049,10 +1049,17 @@ public class BubbleStackView extends FrameLayout
private final Runnable mAnimateTemporarilyInvisibleImmediate = () -> {
if (mTemporarilyInvisible && mFlyout.getVisibility() != View.VISIBLE) {
+ // To calculate a distance, bubble stack needs to be moved to become hidden,
+ // we need to take into account that the bubble stack is positioned on the edge
+ // of the available screen rect, which can be offset by system bars and cutouts.
if (mStackAnimationController.isStackOnLeftSide()) {
- animate().translationX(-mBubbleSize).start();
+ int availableRectOffsetX =
+ mPositioner.getAvailableRect().left - mPositioner.getScreenRect().left;
+ animate().translationX(-(mBubbleSize + availableRectOffsetX)).start();
} else {
- animate().translationX(mBubbleSize).start();
+ int availableRectOffsetX =
+ mPositioner.getAvailableRect().right - mPositioner.getScreenRect().right;
+ animate().translationX(mBubbleSize - availableRectOffsetX).start();
}
} else {
animate().translationX(0).start();
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index ec56d614f2b5..ad1405aa2356 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -25,7 +25,8 @@ import android.util.Log;
/**
* <p>A class for producing sounds that match those produced by various actions
- * taken by the media and camera APIs. </p>
+ * taken by the media and camera APIs. It is recommended to call methods in this class
+ * in a background thread since it relies on binder calls.</p>
*
* <p>This class is recommended for use with the {@link android.hardware.camera2} API, since the
* camera2 API does not play any sounds on its own for any capture or video recording actions.</p>
@@ -109,7 +110,7 @@ public class MediaActionSound {
/**
* <p>Returns true if the application must play the shutter sound in accordance
- * to certain regional restrictions. </p>
+ * to certain regional restrictions.</p>
*
* <p>If this method returns true, applications are strongly recommended to use
* MediaActionSound.play(SHUTTER_CLICK) or START_VIDEO_RECORDING whenever it captures
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 4563259c31f2..e39914db4d0f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -223,19 +223,19 @@ import java.util.concurrent.locks.ReentrantLock;
</thead>
<tbody>
<tr>
- <td>{@code "crop-left"}</td>
+ <td>{@link MediaFormat#KEY_CROP_LEFT}</td>
<td>Integer</td>
<td>The left-coordinate (x) of the crop rectangle</td>
</tr><tr>
- <td>{@code "crop-top"}</td>
+ <td>{@link MediaFormat#KEY_CROP_TOP}</td>
<td>Integer</td>
<td>The top-coordinate (y) of the crop rectangle</td>
</tr><tr>
- <td>{@code "crop-right"}</td>
+ <td>{@link MediaFormat#KEY_CROP_RIGHT}</td>
<td>Integer</td>
<td>The right-coordinate (x) <strong>MINUS 1</strong> of the crop rectangle</td>
</tr><tr>
- <td>{@code "crop-bottom"}</td>
+ <td>{@link MediaFormat#KEY_CROP_BOTTOM}</td>
<td>Integer</td>
<td>The bottom-coordinate (y) <strong>MINUS 1</strong> of the crop rectangle</td>
</tr><tr>
@@ -251,12 +251,16 @@ import java.util.concurrent.locks.ReentrantLock;
<pre class=prettyprint>
MediaFormat format = decoder.getOutputFormat(&hellip;);
int width = format.getInteger(MediaFormat.KEY_WIDTH);
- if (format.containsKey("crop-left") && format.containsKey("crop-right")) {
- width = format.getInteger("crop-right") + 1 - format.getInteger("crop-left");
+ if (format.containsKey(MediaFormat.KEY_CROP_LEFT)
+ && format.containsKey(MediaFormat.KEY_CROP_RIGHT)) {
+ width = format.getInteger(MediaFormat.KEY_CROP_RIGHT) + 1
+ - format.getInteger(MediaFormat.KEY_CROP_LEFT);
}
int height = format.getInteger(MediaFormat.KEY_HEIGHT);
- if (format.containsKey("crop-top") && format.containsKey("crop-bottom")) {
- height = format.getInteger("crop-bottom") + 1 - format.getInteger("crop-top");
+ if (format.containsKey(MediaFormat.KEY_CROP_TOP)
+ && format.containsKey(MediaFormat.KEY_CROP_BOTTOM)) {
+ height = format.getInteger(MediaFormat.KEY_CROP_BOTTOM) + 1
+ - format.getInteger(MediaFormat.KEY_CROP_TOP);
}
</pre>
<p class=note>
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 7d3f91653cea..9dea5b9152b7 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -359,6 +359,42 @@ public final class MediaFormat {
public static final String KEY_HEIGHT = "height";
/**
+ * A key describing the bottom-coordinate (y) of the crop rectangle.
+ * This is the bottom-most row included in the crop frame,
+ * where row indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_BOTTOM = "crop-bottom";
+
+ /**
+ * A key describing the left-coordinate (x) of the crop rectangle.
+ * This is the left-most column included in the crop frame,
+ * where column indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_LEFT = "crop-left";
+
+ /**
+ * A key describing the right-coordinate (x) of the crop rectangle.
+ * This is the right-most column included in the crop frame,
+ * where column indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_RIGHT = "crop-right";
+
+ /**
+ * A key describing the top-coordinate (y) of the crop rectangle.
+ * This is the top-most row included in the crop frame,
+ * where row indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_TOP = "crop-top";
+
+ /**
* A key describing the maximum expected width of the content in a video
* decoder format, in case there are resolution changes in the video content.
* The associated value is an integer
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index ee0293d629b1..283a41a81057 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -539,6 +539,7 @@ public final class MediaRoute2Info implements Parcelable {
/**
* Gets the Deduplication ID of the route if available.
* @see RouteDiscoveryPreference#shouldRemoveDuplicates()
+ * @hide
*/
@NonNull
public Set<String> getDeduplicationIds() {
@@ -968,6 +969,7 @@ public final class MediaRoute2Info implements Parcelable {
* <p>
* If it's {@code null}, the route will not be removed.
* @see RouteDiscoveryPreference#shouldRemoveDuplicates()
+ * @hide
*/
@NonNull
public Builder setDeduplicationIds(@NonNull Set<String> id) {
diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java
index 0ba36feb4ce9..207460af140c 100644
--- a/media/java/android/media/RouteDiscoveryPreference.java
+++ b/media/java/android/media/RouteDiscoveryPreference.java
@@ -119,6 +119,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* first in the provided list will remain.
*
* @see #shouldRemoveDuplicates()
+ * @hide
*/
@NonNull
public List<String> getDeduplicationPackageOrder() {
@@ -130,6 +131,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* <p>
* If it's not empty, it will only discover routes from the provider whose package name
* belongs to the list.
+ * @hide
*/
@NonNull
public List<String> getAllowedPackages() {
@@ -151,6 +153,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* Gets whether duplicate routes removal is enabled.
*
* @see #getDeduplicationPackageOrder()
+ * @hide
*/
public boolean shouldRemoveDuplicates() {
return !mPackageOrder.isEmpty();
@@ -293,6 +296,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* <p>
* If it's non-empty, media router only discovers route from the provider in the list.
* The default value is empty, which discovers routes from all providers.
+ * @hide
*/
@NonNull
public Builder setAllowedPackages(@NonNull List<String> allowedPackages) {
@@ -324,6 +328,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
*
* @param packageOrder ordered list of package names used to remove duplicate routes, or an
* empty list if deduplication should not be enabled.
+ * @hide
*/
@NonNull
public Builder setDeduplicationPackageOrder(@NonNull List<String> packageOrder) {
diff --git a/media/java/android/media/tv/AdRequest.java b/media/java/android/media/tv/AdRequest.java
index 0542c5598c01..f2fb93d803a8 100644
--- a/media/java/android/media/tv/AdRequest.java
+++ b/media/java/android/media/tv/AdRequest.java
@@ -163,7 +163,11 @@ public final class AdRequest implements Parcelable {
/**
* Gets the metadata of the media file.
- * <p>This includes additional information the TV input needs to play the AD media.
+ *
+ * <p>This includes additional information the TV input needs to play the AD media. This may
+ * include fields in {@link android.media.MediaFormat} like
+ * {@link android.media.MediaFormat#KEY_SAMPLE_RATE}, or integrity information like SHA. What
+ * data is included depends on the format of the media file.
*
* @return The metadata of the media file. Can be an empty bundle for
* {@link #REQUEST_TYPE_STOP}.
diff --git a/media/java/android/media/tv/interactive/AppLinkInfo.aidl b/media/java/android/media/tv/interactive/AppLinkInfo.aidl
index 6759fc499e1c..f551c9fcf6c7 100644
--- a/media/java/android/media/tv/interactive/AppLinkInfo.aidl
+++ b/media/java/android/media/tv/interactive/AppLinkInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/AppLinkInfo.java b/media/java/android/media/tv/interactive/AppLinkInfo.java
index 0eb6fa8996d6..3c3905d6c77f 100644
--- a/media/java/android/media/tv/interactive/AppLinkInfo.java
+++ b/media/java/android/media/tv/interactive/AppLinkInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index c8c6f66aa0ed..50aa6febacf7 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index eb012721445c..9ff564ea3737 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -34,7 +34,6 @@ import android.view.Surface;
*/
interface ITvInteractiveAppManager {
List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList(int userId);
- void prepare(String tiasId, int type, int userId);
void registerAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
void unregisterAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
void sendAppLinkCommand(String tiasId, in Bundle command, int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
index f410c0fac488..fed86dc9e0a8 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
index b6d518ff7242..fb58ca7843ef 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -32,7 +32,6 @@ oneway interface ITvInteractiveAppService {
void unregisterCallback(in ITvInteractiveAppServiceCallback callback);
void createSession(in InputChannel channel, in ITvInteractiveAppSessionCallback callback,
in String iAppServiceId, int type);
- void prepare(int type);
void registerAppLinkInfo(in AppLinkInfo info);
void unregisterAppLinkInfo(in AppLinkInfo info);
void sendAppLinkCommand(in Bundle command);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
index 970b94327572..87b3c1df6197 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
index c784b09e87fc..e14b2bb18ea6 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index f74b2bac957b..32b08b7042fe 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index 702832ccb3ca..d3cbcdc9a255 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -30,7 +30,6 @@ import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvContentRating;
import android.media.tv.TvInputManager;
import android.media.tv.TvTrackInfo;
-import android.media.tv.interactive.TvInteractiveAppServiceInfo.InteractiveAppType;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -775,25 +774,6 @@ public final class TvInteractiveAppManager {
}
/**
- * Prepares TV Interactive App service environment for the given type.
- *
- * <p>This method brings up the corresponding {@link TvInteractiveAppService} and prepare needed
- * resources. It's used to set up the resources in advance, or handle non-session operations.
- *
- * @param tvIAppServiceId The ID of TV interactive service to prepare the resources. The
- * ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
- *
- * @see TvInteractiveAppService.Session
- */
- public void prepare(@NonNull String tvIAppServiceId, @InteractiveAppType int type) {
- try {
- mService.prepare(tvIAppServiceId, type, mUserId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Registers an Android application link info record which can be used to launch the specific
* Android application by TV interactive App RTE.
*
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 15144f82e52c..b103b1036303 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -218,11 +218,6 @@ public abstract class TvInteractiveAppService extends Service {
}
@Override
- public void prepare(int type) {
- onPrepare(type);
- }
-
- @Override
public void registerAppLinkInfo(AppLinkInfo appLinkInfo) {
onRegisterAppLinkInfo(appLinkInfo);
}
@@ -241,11 +236,6 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
- * Prepares TV Interactive App service for the given type.
- */
- public abstract void onPrepare(@TvInteractiveAppServiceInfo.InteractiveAppType int type);
-
- /**
* Called when a request to register an Android application link info record is received.
*/
public void onRegisterAppLinkInfo(@NonNull AppLinkInfo appLinkInfo) {
@@ -407,9 +397,10 @@ public abstract class TvInteractiveAppService extends Service {
* no matter if it's created successfully or not.
*
* @see #notifyBiInteractiveAppCreated(Uri, String)
- * @see #onDestroyBiInteractiveApp(String)
+ * @see #onDestroyBiInteractiveAppRequest(String)
*/
- public void onCreateBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+ public void onCreateBiInteractiveAppRequest(
+ @NonNull Uri biIAppUri, @Nullable Bundle params) {
}
@@ -417,11 +408,11 @@ public abstract class TvInteractiveAppService extends Service {
* Destroys broadcast-independent(BI) interactive application.
*
* @param biIAppId the BI interactive app ID from
- * {@link #onCreateBiInteractiveApp(Uri, Bundle)}}
+ * {@link #onCreateBiInteractiveAppRequest(Uri, Bundle)}
*
- * @see #onCreateBiInteractiveApp(Uri, Bundle)
+ * @see #onCreateBiInteractiveAppRequest(Uri, Bundle)
*/
- public void onDestroyBiInteractiveApp(@NonNull String biIAppId) {
+ public void onDestroyBiInteractiveAppRequest(@NonNull String biIAppId) {
}
/**
@@ -978,11 +969,11 @@ public abstract class TvInteractiveAppService extends Service {
}
void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
- onCreateBiInteractiveApp(biIAppUri, params);
+ onCreateBiInteractiveAppRequest(biIAppUri, params);
}
void destroyBiInteractiveApp(@NonNull String biIAppId) {
- onDestroyBiInteractiveApp(biIAppId);
+ onDestroyBiInteractiveAppRequest(biIAppId);
}
void setTeletextAppEnabled(boolean enable) {
@@ -1142,7 +1133,7 @@ public abstract class TvInteractiveAppService extends Service {
* @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
* app. {@code null} if it's not created successfully.
*
- * @see #onCreateBiInteractiveApp(Uri, Bundle)
+ * @see #onCreateBiInteractiveAppRequest(Uri, Bundle)
*/
@CallSuper
public final void notifyBiInteractiveAppCreated(
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
index 49600a05cb7f..4b6127c01d1e 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
index ee6fb047567c..3e0885214dcd 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 9154de008d7a..1df757b2d9d7 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -83,6 +83,19 @@ public class TvInteractiveAppView extends ViewGroup {
* @see java.security.PrivateKey
*/
public static final String BI_INTERACTIVE_APP_KEY_PRIVATE_KEY = "private_key";
+ /**
+ * Additional HTTP headers to be used by {@link TvInteractiveAppService} to load the
+ * broadcast-independent interactive application.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS =
+ "http_additional_headers";
+ /**
+ * HTTP user agent to be used by {@link TvInteractiveAppService} for broadcast-independent
+ * interactive application.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT = "http_user_agent";
private final TvInteractiveAppManager mTvInteractiveAppManager;
private final Handler mHandler = new Handler();
@@ -595,7 +608,14 @@ public class TvInteractiveAppView extends ViewGroup {
* <p>{@link TvInteractiveAppCallback#onBiInteractiveAppCreated(String, Uri, String)} will be
* called for the result.
*
+ * @param biIAppUri URI associated this BI interactive app.
+ * @param params optional parameters for broadcast-independent interactive application, such as
+ * {@link #BI_INTERACTIVE_APP_KEY_CERTIFICATE}.
+ *
* @see TvInteractiveAppCallback#onBiInteractiveAppCreated(String, Uri, String)
+ * @see #BI_INTERACTIVE_APP_KEY_CERTIFICATE
+ * @see #BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS
+ * @see #BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT
*/
public void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
if (DEBUG) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index e4efae2f1a36..7e8ce2b5b29d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -23,12 +23,15 @@ import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.res.TypedArray;
+import android.os.Build;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
+import androidx.annotation.RequiresApi;
+import androidx.core.os.BuildCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
@@ -102,11 +105,9 @@ public class RestrictedPreferenceHelper {
if (mDisabledSummary) {
final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
if (summaryView != null) {
- final CharSequence disabledText = mContext
- .getSystemService(DevicePolicyManager.class)
- .getString(CONTROLLED_BY_ADMIN_SUMMARY,
- () -> summaryView.getContext().getString(
- R.string.disabled_by_admin_summary_text));
+ final CharSequence disabledText = BuildCompat.isAtLeastT()
+ ? getDisabledByAdminUpdatableString()
+ : mContext.getString(R.string.disabled_by_admin_summary_text);
if (mDisabledByAdmin) {
summaryView.setText(disabledText);
} else if (mDisabledByAppOps) {
@@ -119,6 +120,13 @@ public class RestrictedPreferenceHelper {
}
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private String getDisabledByAdminUpdatableString() {
+ return mContext.getSystemService(DevicePolicyManager.class).getString(
+ CONTROLLED_BY_ADMIN_SUMMARY,
+ () -> mContext.getString(R.string.disabled_by_admin_summary_text));
+ }
+
public void useAdminDisabledSummary(boolean useSummary) {
mDisabledSummary = useSummary;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 19114cf147e4..38fad9d99aa4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -30,6 +30,7 @@ import android.net.TetheringManager;
import android.net.vcn.VcnTransportInfo;
import android.net.wifi.WifiInfo;
import android.os.BatteryManager;
+import android.os.Build;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -41,8 +42,10 @@ import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import androidx.core.os.BuildCompat;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.UserIcons;
@@ -127,8 +130,9 @@ public class Utils {
String name = info != null ? info.name : null;
if (info.isManagedProfile()) {
// We use predefined values for managed profiles
- return context.getSystemService(DevicePolicyManager.class).getString(
- WORK_PROFILE_USER_LABEL, () -> context.getString(R.string.managed_user_title));
+ return BuildCompat.isAtLeastT()
+ ? getUpdatableManagedUserTitle(context)
+ : context.getString(R.string.managed_user_title);
} else if (info.isGuest()) {
name = context.getString(R.string.user_guest);
}
@@ -140,6 +144,13 @@ public class Utils {
return context.getResources().getString(R.string.running_process_item_user_label, name);
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private static String getUpdatableManagedUserTitle(Context context) {
+ return context.getSystemService(DevicePolicyManager.class).getString(
+ WORK_PROFILE_USER_LABEL,
+ () -> context.getString(R.string.managed_user_title));
+ }
+
/**
* Returns a circular icon for a user.
*/
diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
index c61f8a9c3b53..be420ac8bd24 100644
--- a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
@@ -31,6 +31,8 @@ import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+
/**
* An interface class to manage connectivity subsystem recovery/restart operations.
*/
@@ -193,22 +195,30 @@ public class ConnectivitySubsystemsRecoveryManager {
mApmMonitorRegistered = false;
}
- private void startTrackingWifiRestart() {
+ @VisibleForTesting
+ void startTrackingWifiRestart() {
+ if (mWifiManager == null) return;
mWifiManager.registerSubsystemRestartTrackingCallback(new HandlerExecutor(mHandler),
mWifiSubsystemRestartTrackingCallback);
}
- private void stopTrackingWifiRestart() {
+ @VisibleForTesting
+ void stopTrackingWifiRestart() {
+ if (mWifiManager == null) return;
mWifiManager.unregisterSubsystemRestartTrackingCallback(
mWifiSubsystemRestartTrackingCallback);
}
- private void startTrackingTelephonyRestart() {
+ @VisibleForTesting
+ void startTrackingTelephonyRestart() {
+ if (mTelephonyManager == null) return;
mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(mHandler),
mTelephonyCallback);
}
- private void stopTrackingTelephonyRestart() {
+ @VisibleForTesting
+ void stopTrackingTelephonyRestart() {
+ if (mTelephonyManager == null) return;
mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java
new file mode 100644
index 000000000000..ca53a187d6f8
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 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.connectivity;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class ConnectivitySubsystemsRecoveryManagerTest {
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Spy
+ Context mContext = ApplicationProvider.getApplicationContext();
+ @Spy
+ Handler mMainHandler = ApplicationProvider.getApplicationContext().getMainThreadHandler();
+ @Mock
+ PackageManager mPackageManager;
+
+ ConnectivitySubsystemsRecoveryManager mConnectivitySubsystemsRecoveryManager;
+
+ @Before
+ public void setUp() {
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
+ }
+
+ @Test
+ public void startTrackingWifiRestart_hasNoWifiFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.startTrackingWifiRestart();
+ }
+
+ @Test
+ public void stopTrackingWifiRestart_hasNoWifiFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.stopTrackingWifiRestart();
+ }
+
+ @Test
+ public void startTrackingTelephonyRestart_hasNoTelephonyFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.startTrackingTelephonyRestart();
+ }
+
+ @Test
+ public void stopTrackingTelephonyRestart_hasNoTelephonyFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.stopTrackingTelephonyRestart();
+ }
+}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e24b2d6c6aa9..4b45cc338a6a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -314,6 +314,11 @@
<!-- To change system captions state -->
<uses-permission android:name="android.permission.SET_SYSTEM_AUDIO_CAPTION" />
+ <!-- Compat framework -->
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 8d205c14144d..9a6f5edae5ec 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -129,4 +129,7 @@
<dimen name="user_switcher_icon_selected_width">8dp</dimen>
<dimen name="user_switcher_fullscreen_button_text_size">14sp</dimen>
<dimen name="user_switcher_fullscreen_button_padding">12dp</dimen>
+
+ <!-- Translation y for appear animation -->
+ <dimen name="keyguard_host_view_translation_y">80dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/drawable/media_ttt_undo_background.xml b/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
index ec74ee1fcbf1..3e2e4f055b14 100644
--- a/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
+++ b/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
@@ -14,9 +14,14 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape
+<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <solid android:color="?androidprv:attr/colorAccentPrimary" />
- <corners android:radius="24dp" />
-</shape>
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:color="?android:textColorPrimary">
+ <item android:id="@android:id/background">
+ <shape>
+ <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+ <corners android:radius="24dp" />
+ </shape>
+ </item>
+</ripple>
diff --git a/packages/SystemUI/res/drawable/user_switcher_icon_large.xml b/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
index 1ed75537059a..d81b518d2a9f 100644
--- a/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
+++ b/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
@@ -27,7 +27,7 @@
</shape>
</item>
<!-- When an item is selected, this layer will show a ring around the icon -->
- <item>
+ <item android:id="@+id/ring">
<shape android:shape="oval">
<stroke
android:width="@dimen/user_switcher_icon_selected_width"
@@ -35,7 +35,7 @@
</shape>
</item>
<!-- Where the user drawable/bitmap will be placed -->
- <item
+ <item android:id="@+id/user_avatar"
android:drawable="@drawable/user_avatar_bg"
android:width="@dimen/bouncer_user_switcher_icon_size"
android:height="@dimen/bouncer_user_switcher_icon_size"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index a0a876825a6f..9ea361892b32 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -707,4 +707,18 @@
<integer name="complicationFadeInMs">500</integer>
<integer name="complicationRestoreMs">1000</integer>
+
+ <!-- Icons that don't show in a collapsed non-keyguard statusbar -->
+ <string-array name="config_collapsed_statusbar_icon_blocklist" translatable="false">
+ <item>@*android:string/status_bar_volume</item>
+ <item>@*android:string/status_bar_alarm_clock</item>
+ <item>@*android:string/status_bar_call_strength</item>
+ </string-array>
+
+ <!-- Icons that don't show in a collapsed statusbar on keyguard -->
+ <string-array name="config_keyguard_statusbar_icon_blocklist" translatable="false">
+ <item>@*android:string/status_bar_volume</item>
+ <item>@*android:string/status_bar_alarm_clock</item>
+ <item>@*android:string/status_bar_call_strength</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6871310ebd6b..8f4e11527d95 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1008,6 +1008,9 @@
<!-- Media tap-to-transfer chip for receiver device -->
<dimen name="media_ttt_chip_size_receiver">100dp</dimen>
<dimen name="media_ttt_icon_size_receiver">95dp</dimen>
+ <!-- Since the generic icon isn't circular, we need to scale it down so it still fits within
+ the circular chip. -->
+ <dimen name="media_ttt_generic_icon_size_receiver">70dp</dimen>
<!-- Window magnification -->
<dimen name="magnification_border_drag_size">35dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d230f33f4939..6dc6214fec65 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2184,7 +2184,7 @@
<!-- Text informing the user that their media is now playing on this device. [CHAR LIMIT=50] -->
<string name="media_transfer_playing_this_device">Playing on this phone</string>
<!-- Text informing the user that the media transfer has failed because something went wrong. [CHAR LIMIT=50] -->
- <string name="media_transfer_failed">Something went wrong</string>
+ <string name="media_transfer_failed">Something went wrong. Try again.</string>
<!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
<string name="controls_error_timeout">Inactive, check app</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt b/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt
new file mode 100644
index 000000000000..497d81f6bdc5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.keyguard
+
+import android.util.MathUtils
+
+object BouncerPanelExpansionCalculator {
+ /**
+ * Scale the alpha/position of the host view.
+ */
+ @JvmStatic
+ fun getHostViewScaledExpansion(fraction: Float): Float {
+ return when {
+ fraction >= 0.9f -> 1f
+ fraction < 0.6 -> 0f
+ else -> (fraction - 0.6f) / 0.3f
+ }
+ }
+
+ /**
+ * Scale the alpha/tint of the back scrim.
+ */
+ @JvmStatic
+ fun getBackScrimScaledExpansion(fraction: Float): Float {
+ return MathUtils.constrain((fraction - 0.9f) / 0.1f, 0f, 1f)
+ }
+
+ /**
+ * This will scale the alpha/position of the clock.
+ */
+ @JvmStatic
+ fun getKeyguardClockScaledExpansion(fraction: Float): Float {
+ return MathUtils.constrain((fraction - 0.7f) / 0.3f, 0f, 1f)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index b6910961bcb4..8c3e066849b9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -37,7 +37,6 @@ import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.util.ViewController;
import java.io.File;
@@ -64,6 +63,7 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
private ActivityStarter.OnDismissAction mDismissAction;
private Runnable mCancelAction;
+ private int mTranslationY;
private final KeyguardUpdateMonitorCallback mUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@@ -322,12 +322,14 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
/**
* Fades and translates in/out the security screen.
+ * Fades in as expansion approaches 0.
+ * Animation duration is between 0.33f and 0.67f of panel expansion fraction.
* @param fraction amount of the screen that should show.
*/
public void setExpansion(float fraction) {
- float alpha = MathUtils.map(KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
- mView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
- mView.setTranslationY(fraction * mView.getHeight());
+ float scaledFraction = BouncerPanelExpansionCalculator.getHostViewScaledExpansion(fraction);
+ mView.setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
+ mView.setTranslationY(scaledFraction * mTranslationY);
}
/**
@@ -490,6 +492,8 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
}
+ mTranslationY = resources
+ .getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y);
// Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
// We're just changing the gravity here though (which can't be applied to RelativeLayout),
// so only attempt the update if mView is inside a FrameLayout.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 362fbed7055a..46a883194e25 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -152,6 +152,7 @@ public class KeyguardSecurityContainer extends FrameLayout {
private SwipeListener mSwipeListener;
private ViewMode mViewMode = new DefaultViewMode();
private @Mode int mCurrentMode = MODE_DEFAULT;
+ private int mWidth = -1;
private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -649,9 +650,11 @@ public class KeyguardSecurityContainer extends FrameLayout {
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- // After a layout pass, we need to re-place the inner bouncer, as our bounds may have
- // changed.
- mViewMode.updateSecurityViewLocation();
+ int width = right - left;
+ if (changed && mWidth != width) {
+ mWidth = width;
+ mViewMode.updateSecurityViewLocation();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 74659f71eb1f..e36e984380e2 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -211,6 +211,23 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mDownDetected = false;
updateBurnInOffsets();
updateVisibility();
+
+ updateAccessibility();
+ }
+
+ private void updateAccessibility() {
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ mView.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onLongPress();
+ }
+ }
+ );
+ } else {
+ mView.setOnClickListener(null);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index bc7a3f6f4b13..975e0c5b32cd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -49,7 +49,6 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.VelocityTracker;
-import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -92,7 +91,7 @@ import kotlin.Unit;
* Note that the current architecture is designed so that a single {@link UdfpsController}
* controls/manages all UDFPS sensors. In other words, a single controller is registered with
* {@link com.android.server.biometrics.sensors.fingerprint.FingerprintService}, and interfaces such
- * as {@link FingerprintManager#onPointerDown(int, int, int, float, float)} or
+ * as {@link FingerprintManager#onPointerDown(long, int, int, int, float, float)} or
* {@link IUdfpsOverlayController#showUdfpsOverlay} should all have
* {@code sensorId} parameters.
*/
@@ -193,7 +192,7 @@ public class UdfpsController implements DozeReceiver {
public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
@Override
- public void showUdfpsOverlay(int sensorId, int reason,
+ public void showUdfpsOverlay(long requestId, int sensorId, int reason,
@NonNull IUdfpsOverlayControllerCallback callback) {
mFgExecutor.execute(
() -> UdfpsController.this.showUdfpsOverlay(new UdfpsControllerOverlay(
@@ -203,8 +202,10 @@ public class UdfpsController implements DozeReceiver {
mKeyguardUpdateMonitor, mDialogManager, mDumpManager,
mLockscreenShadeTransitionController, mConfigurationController,
mSystemClock, mKeyguardStateController,
- mUnlockedScreenOffAnimationController, mSensorProps, mHbmProvider,
- reason, callback, UdfpsController.this::onTouch,
+ mUnlockedScreenOffAnimationController, mSensorProps,
+ mHbmProvider, requestId, reason, callback,
+ (view, event, fromUdfpsView) ->
+ onTouch(requestId, event, fromUdfpsView),
mActivityLaunchAnimator)));
}
@@ -318,7 +319,8 @@ public class UdfpsController implements DozeReceiver {
if (mOverlay == null || mOverlay.isHiding()) {
return false;
}
- return onTouch(mOverlay.getOverlayView(), event, false);
+ // TODO(b/225068271): may not be correct but no way to get the id yet
+ return onTouch(mOverlay.getRequestId(), event, false);
}
/**
@@ -342,8 +344,18 @@ public class UdfpsController implements DozeReceiver {
&& getSensorLocation().contains(x, y);
}
- private boolean onTouch(@NonNull View view, @NonNull MotionEvent event, boolean fromUdfpsView) {
- UdfpsView udfpsView = (UdfpsView) view;
+ private boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
+ if (mOverlay == null) {
+ Log.w(TAG, "ignoring onTouch with null overlay");
+ return false;
+ }
+ if (!mOverlay.matchesRequestId(requestId)) {
+ Log.w(TAG, "ignoring stale touch event: " + requestId + " current: "
+ + mOverlay.getRequestId());
+ return false;
+ }
+
+ final UdfpsView udfpsView = mOverlay.getOverlayView();
final boolean isIlluminationRequested = udfpsView.isIlluminationRequested();
boolean handled = false;
switch (event.getActionMasked()) {
@@ -453,7 +465,7 @@ public class UdfpsController implements DozeReceiver {
// Do nothing to stay in portrait mode.
}
- onFingerDown(x, y, minor, major);
+ onFingerDown(requestId, x, y, minor, major);
Log.v(TAG, "onTouch | finger down: " + touchInfo);
mTouchLogTime = mSystemClock.elapsedRealtime();
mPowerManager.userActivity(mSystemClock.uptimeMillis(),
@@ -465,7 +477,7 @@ public class UdfpsController implements DozeReceiver {
}
} else {
Log.v(TAG, "onTouch | finger outside");
- onFingerUp(udfpsView);
+ onFingerUp(requestId, udfpsView);
}
}
Trace.endSection();
@@ -482,7 +494,7 @@ public class UdfpsController implements DozeReceiver {
}
Log.v(TAG, "onTouch | finger up");
mAttemptedToDismissKeyguard = false;
- onFingerUp(udfpsView);
+ onFingerUp(requestId, udfpsView);
mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
Trace.endSection();
break;
@@ -679,7 +691,7 @@ public class UdfpsController implements DozeReceiver {
// Reset the controller back to its starting state.
final UdfpsView oldView = mOverlay.getOverlayView();
if (oldView != null) {
- onFingerUp(oldView);
+ onFingerUp(mOverlay.getRequestId(), oldView);
}
final boolean removed = mOverlay.hide();
if (mKeyguardViewManager.isShowingAlternateAuth()) {
@@ -710,6 +722,8 @@ public class UdfpsController implements DozeReceiver {
return;
}
+ // TODO(b/225068271): this may not be correct but there isn't a way to track it
+ final long requestId = mOverlay != null ? mOverlay.getRequestId() : -1;
mAodInterruptRunnable = () -> {
mIsAodInterruptActive = true;
// Since the sensor that triggers the AOD interrupt doesn't provide
@@ -719,10 +733,10 @@ public class UdfpsController implements DozeReceiver {
mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelUdfps,
AOD_INTERRUPT_TIMEOUT_MILLIS);
// using a hard-coded value for major and minor until it is available from the sensor
- onFingerDown(screenX, screenY, minor, major);
+ onFingerDown(requestId, screenX, screenY, minor, major);
};
- if (mScreenOn && mAodInterruptRunnable != null) {
+ if (mScreenOn) {
mAodInterruptRunnable.run();
mAodInterruptRunnable = null;
}
@@ -755,7 +769,7 @@ public class UdfpsController implements DozeReceiver {
*/
void onCancelUdfps() {
if (mOverlay != null && mOverlay.getOverlayView() != null) {
- onFingerUp(mOverlay.getOverlayView());
+ onFingerUp(mOverlay.getRequestId(), mOverlay.getOverlayView());
}
if (!mIsAodInterruptActive) {
return;
@@ -771,12 +785,17 @@ public class UdfpsController implements DozeReceiver {
return mOnFingerDown;
}
- private void onFingerDown(int x, int y, float minor, float major) {
+ private void onFingerDown(long requestId, int x, int y, float minor, float major) {
mExecution.assertIsMainThread();
if (mOverlay == null) {
Log.w(TAG, "Null request in onFingerDown");
return;
}
+ if (!mOverlay.matchesRequestId(requestId)) {
+ Log.w(TAG, "Mismatched fingerDown: " + requestId
+ + " current: " + mOverlay.getRequestId());
+ return;
+ }
if (mOverlay.getAnimationViewController() instanceof UdfpsKeyguardViewController
&& !mStatusBarStateController.isDozing()) {
@@ -791,14 +810,14 @@ public class UdfpsController implements DozeReceiver {
}
}
mOnFingerDown = true;
- mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
+ mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, x, y, minor, major);
Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
final UdfpsView view = mOverlay.getOverlayView();
if (view != null) {
Trace.beginAsyncSection("UdfpsController.e2e.startIllumination", 0);
view.startIllumination(() -> {
- mFingerprintManager.onUiReady(mSensorProps.sensorId);
+ mFingerprintManager.onUiReady(requestId, mSensorProps.sensorId);
mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
Trace.endAsyncSection("UdfpsController.e2e.startIllumination", 0);
});
@@ -809,12 +828,12 @@ public class UdfpsController implements DozeReceiver {
}
}
- private void onFingerUp(@NonNull UdfpsView view) {
+ private void onFingerUp(long requestId, @NonNull UdfpsView view) {
mExecution.assertIsMainThread();
mActivePointerId = -1;
mAcquiredReceived = false;
if (mOnFingerDown) {
- mFingerprintManager.onPointerUp(mSensorProps.sensorId);
+ mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId);
for (Callback cb : mCallbacks) {
cb.onFingerUp();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 086894d2e670..ee43e932b344 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -80,6 +80,7 @@ class UdfpsControllerOverlay(
private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
private val sensorProps: FingerprintSensorPropertiesInternal,
private var hbmProvider: UdfpsHbmProvider,
+ val requestId: Long,
@ShowReason val requestReason: Int,
private val controllerCallback: IUdfpsOverlayControllerCallback,
private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
@@ -276,6 +277,9 @@ class UdfpsControllerOverlay(
}
}
+ /** Checks if the id is relevant for this overlay. */
+ fun matchesRequestId(id: Long): Boolean = requestId == -1L || requestId == id
+
private fun WindowManager.LayoutParams.updateForLocation(
location: SensorLocationInternal,
animation: UdfpsAnimationViewController<*>?
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index f78929f75b04..a9f340854689 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -35,6 +35,7 @@ import com.android.systemui.power.PowerUI
import com.android.systemui.recents.Recents
import com.android.systemui.shortcut.ShortcutKeyDispatcher
import com.android.systemui.statusbar.notification.InstantAppNotifier
+import com.android.systemui.statusbar.phone.KeyguardLiftController
import com.android.systemui.theme.ThemeOverlayController
import com.android.systemui.toast.ToastUI
import com.android.systemui.usb.StorageNotification
@@ -198,4 +199,10 @@ abstract class SystemUICoreStartableModule {
@IntoMap
@ClassKey(WMShell::class)
abstract fun bindWMShell(sysui: WMShell): CoreStartable
+
+ /** Inject into KeyguardLiftController. */
+ @Binds
+ @IntoMap
+ @ClassKey(KeyguardLiftController::class)
+ abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
index d2ab61149d26..59a17bad5069 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
@@ -88,10 +88,6 @@ public class DreamOverlayStatusBarView extends ConstraintLayout {
fetchStatusIconForResId(R.id.dream_overlay_priority_mode));
}
- void showIcon(@StatusIconType int iconType, boolean show) {
- showIcon(iconType, show, null);
- }
-
void showIcon(@StatusIconType int iconType, boolean show, @Nullable String contentDescription) {
View icon = mStatusIcons.get(iconType);
if (icon == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index a25a7423770e..761f28c5ac3b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -16,6 +16,7 @@
package com.android.systemui.dreams;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.res.Resources;
import android.hardware.SensorPrivacyManager;
@@ -45,6 +46,7 @@ import com.android.systemui.util.time.DateFormatUtil;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -62,6 +64,9 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
private final IndividualSensorPrivacyController mSensorPrivacyController;
private final NotificationListener mNotificationListener;
private final ZenModeController mZenModeController;
+ private final Executor mMainExecutor;
+
+ private boolean mIsAttached;
private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
.clearCapabilities()
@@ -131,6 +136,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
public DreamOverlayStatusBarViewController(
DreamOverlayStatusBarView view,
@Main Resources resources,
+ @Main Executor mainExecutor,
ConnectivityManager connectivityManager,
TouchInsetManager.TouchInsetSession touchInsetSession,
AlarmManager alarmManager,
@@ -141,6 +147,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
ZenModeController zenModeController) {
super(view);
mResources = resources;
+ mMainExecutor = mainExecutor;
mConnectivityManager = connectivityManager;
mTouchInsetSession = touchInsetSession;
mAlarmManager = alarmManager;
@@ -157,6 +164,8 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
@Override
protected void onViewAttached() {
+ mIsAttached = true;
+
updateNotificationsStatusIcon();
mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
@@ -181,6 +190,8 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
mNextAlarmController.removeCallback(mNextAlarmCallback);
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
mTouchInsetSession.clear();
+
+ mIsAttached = false;
}
private void updateWifiUnavailableStatusIcon() {
@@ -189,14 +200,14 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
mConnectivityManager.getActiveNetwork());
final boolean available = capabilities != null
&& capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
- mView.showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available);
+ showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available);
}
private void updateAlarmStatusIcon() {
final AlarmManager.AlarmClockInfo alarm =
mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET,
hasAlarm,
hasAlarm ? buildAlarmContentDescription(alarm) : null);
@@ -215,7 +226,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE);
final boolean cameraBlocked = mSensorPrivacyController
.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA);
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED,
micBlocked && cameraBlocked);
}
@@ -230,7 +241,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
final StatusBarNotification[] notifications =
mNotificationListener.getActiveNotifications();
final int notificationCount = notifications != null ? notifications.length : 0;
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS,
notificationCount > 0,
notificationCount > 0
@@ -246,8 +257,23 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
}
private void updatePriorityModeStatusIcon() {
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON,
mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF);
}
+
+ private void showIcon(@DreamOverlayStatusBarView.StatusIconType int iconType, boolean show) {
+ showIcon(iconType, show, null);
+ }
+
+ private void showIcon(
+ @DreamOverlayStatusBarView.StatusIconType int iconType,
+ boolean show,
+ @Nullable String contentDescription) {
+ mMainExecutor.execute(() -> {
+ if (mIsAttached) {
+ mView.showIcon(iconType, show, contentDescription);
+ }
+ });
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 2db3de173257..61cfe925f640 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -145,7 +145,7 @@ public class Flags {
/***************************************/
// 900 - media
public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, true);
- public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, true);
+ public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, false);
public static final BooleanFlag MEDIA_SESSION_LAYOUT = new BooleanFlag(902, true);
public static final BooleanFlag MEDIA_NEARBY_DEVICES = new BooleanFlag(903, true);
public static final BooleanFlag MEDIA_MUTE_AWAIT = new BooleanFlag(904, true);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index c69f947f5f3f..71dfa7433c32 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -16,10 +16,8 @@
package com.android.systemui.keyguard.dagger;
-import android.annotation.Nullable;
import android.app.trust.TrustManager;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.PowerManager;
import com.android.internal.jank.InteractionJankMonitor;
@@ -44,18 +42,14 @@ import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.sensors.AsyncSensorManager;
import java.util.concurrent.Executor;
@@ -133,20 +127,4 @@ public class KeyguardModule {
notificationShadeWindowController,
activityLaunchAnimator);
}
-
- @SysUISingleton
- @Provides
- @Nullable
- static KeyguardLiftController provideKeyguardLiftController(
- Context context,
- StatusBarStateController statusBarStateController,
- AsyncSensorManager asyncSensorManager,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- DumpManager dumpManager) {
- if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
- return null;
- }
- return new KeyguardLiftController(statusBarStateController, asyncSensorManager,
- keyguardUpdateMonitor, dumpManager);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 510d15bd7b73..ffdd5376b12e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -137,7 +137,6 @@ public class MediaControlPanel {
private MediaCarouselController mMediaCarouselController;
private final MediaOutputDialogFactory mMediaOutputDialogFactory;
private final FalsingManager mFalsingManager;
- private final MediaFlags mMediaFlags;
// Used for swipe-to-dismiss logging.
protected boolean mIsImpressed = false;
@@ -156,7 +155,7 @@ public class MediaControlPanel {
Lazy<MediaDataManager> lazyMediaDataManager,
MediaOutputDialogFactory mediaOutputDialogFactory,
MediaCarouselController mediaCarouselController,
- FalsingManager falsingManager, MediaFlags mediaFlags, SystemClock systemClock) {
+ FalsingManager falsingManager, SystemClock systemClock) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
@@ -167,7 +166,6 @@ public class MediaControlPanel {
mMediaOutputDialogFactory = mediaOutputDialogFactory;
mMediaCarouselController = mediaCarouselController;
mFalsingManager = falsingManager;
- mMediaFlags = mediaFlags;
mSystemClock = systemClock;
loadDimens();
@@ -506,9 +504,8 @@ public class MediaControlPanel {
List<MediaAction> actionIcons = data.getActions();
List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
- // If the session actions flag is enabled, but we're still using the regular layout, use
- // the session actions anyways
- if (mMediaFlags.areMediaSessionActionsEnabled() && data.getSemanticActions() != null) {
+ // If we got session actions, use those instead
+ if (data.getSemanticActions() != null) {
MediaButton semanticActions = data.getSemanticActions();
actionIcons = new ArrayList<MediaAction>();
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 9e14fe91f21d..56d8c6486631 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -610,7 +610,8 @@ class MediaDataManager(
var actionIcons: List<MediaAction> = emptyList()
var actionsToShowCollapsed: List<Int> = emptyList()
var semanticActions: MediaButton? = null
- if (mediaFlags.areMediaSessionActionsEnabled() && mediaController.playbackState != null) {
+ if (mediaFlags.areMediaSessionActionsEnabled(sbn.packageName, sbn.user) &&
+ mediaController.playbackState != null) {
semanticActions = createActionsFromState(sbn.packageName, mediaController)
} else {
val actions = createActionsFromNotification(sbn)
@@ -726,7 +727,7 @@ class MediaDataManager(
}
}
- // Finally, assign the remaining button slots: C A play/pause B D
+ // Finally, assign the remaining button slots: play/pause A B C D
// A = previous, else custom action (if not reserved)
// B = next, else custom action (if not reserved)
// C and D are always custom actions
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
index dd35a9a81399..59237d936d72 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
@@ -16,6 +16,8 @@
package com.android.systemui.media
+import android.app.StatusBarManager
+import android.os.UserHandle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -26,16 +28,17 @@ class MediaFlags @Inject constructor(private val featureFlags: FeatureFlags) {
/**
* Check whether media control actions should be based on PlaybackState instead of notification
*/
- fun areMediaSessionActionsEnabled(): Boolean {
- return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS)
+ fun areMediaSessionActionsEnabled(packageName: String, user: UserHandle): Boolean {
+ val enabled = StatusBarManager.useMediaSessionActionsForApp(packageName, user)
+ // Allow global override with flag
+ return enabled || featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS)
}
/**
* Check whether media controls should use the new session-based layout
*/
fun useMediaSessionLayout(): Boolean {
- return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS) &&
- featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT)
+ return featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT)
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
index 3961f079748b..e4b8874ff601 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -128,19 +128,21 @@ class MediaTttCommandLineHelper @Inject constructor(
as StatusBarManager
val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
.addFeature("feature")
- .setPackageName(TEST_PACKAGE_NAME)
- .build()
+ if (args.size >= 2 && args[1] == "useAppIcon=true") {
+ routeInfo.setPackageName(TEST_PACKAGE_NAME)
+ }
statusBarManager.updateMediaTapToTransferReceiverDisplay(
displayState,
- routeInfo,
+ routeInfo.build(),
null,
null
)
}
override fun help(pw: PrintWriter) {
- pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND <chipState>")
+ pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND " +
+ "<chipState> useAppIcon=[true|false]")
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
index 3d5b3a3f70df..54b0c1345601 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -31,6 +31,7 @@ import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
+import android.widget.LinearLayout
import com.android.internal.widget.CachingIconView
import com.android.settingslib.Utils
import com.android.systemui.R
@@ -137,6 +138,11 @@ abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
abstract fun updateChipView(chipInfo: T, currentChipView: ViewGroup)
/**
+ * Returns the size that the icon should be, or null if no size override is needed.
+ */
+ open fun getIconSize(isAppIcon: Boolean): Int? = null
+
+ /**
* An internal method to set the icon on the view.
*
* This is in the common superclass since both the sender and the receiver show an icon.
@@ -151,35 +157,47 @@ abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
appNameOverride: CharSequence? = null,
) {
val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
- val appInfo = getAppInfo(appPackageName)
- appIconView.contentDescription = appNameOverride ?: appInfo.appName
- appIconView.setImageDrawable(appIconDrawableOverride ?: appInfo.appIcon)
+ val iconInfo = getIconInfo(appPackageName)
+
+ getIconSize(iconInfo.isAppIcon)?.let { size ->
+ val lp = appIconView.layoutParams
+ lp.width = size
+ lp.height = size
+ appIconView.layoutParams = lp
+ }
+
+ appIconView.contentDescription = appNameOverride ?: iconInfo.iconName
+ appIconView.setImageDrawable(appIconDrawableOverride ?: iconInfo.icon)
}
/**
- * Returns the app name and icon of the app playing media, or a default name and icon if we
- * can't find the app name/icon.
+ * Returns the information needed to display the icon.
+ *
+ * The information will either contain app name and icon of the app playing media, or a default
+ * name and icon if we can't find the app name/icon.
*/
- private fun getAppInfo(appPackageName: String?): AppInfo {
+ private fun getIconInfo(appPackageName: String?): IconInfo {
if (appPackageName != null) {
try {
- return AppInfo(
- appName = context.packageManager.getApplicationInfo(
+ return IconInfo(
+ iconName = context.packageManager.getApplicationInfo(
appPackageName, PackageManager.ApplicationInfoFlags.of(0)
).loadLabel(context.packageManager).toString(),
- appIcon = context.packageManager.getApplicationIcon(appPackageName)
+ icon = context.packageManager.getApplicationIcon(appPackageName),
+ isAppIcon = true
)
} catch (e: PackageManager.NameNotFoundException) {
Log.w(TAG, "Cannot find package $appPackageName", e)
}
}
- return AppInfo(
- appName = context.getString(R.string.media_output_dialog_unknown_launch_app_name),
- appIcon = context.resources.getDrawable(R.drawable.ic_cast).apply {
+ return IconInfo(
+ iconName = context.getString(R.string.media_output_dialog_unknown_launch_app_name),
+ icon = context.resources.getDrawable(R.drawable.ic_cast).apply {
this.setTint(
Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
)
- }
+ },
+ isAppIcon = false
)
}
@@ -203,7 +221,9 @@ object MediaTttRemovalReason {
const val REASON_SCREEN_TAP = "SCREEN_TAP"
}
-private data class AppInfo(
- val appName: String,
- val appIcon: Drawable
+private data class IconInfo(
+ val iconName: String,
+ val icon: Drawable,
+ /** True if [icon] is the app's icon, and false if [icon] is some generic default icon. */
+ val isAppIcon: Boolean
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 44965d705802..072263fcf38c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -127,6 +127,15 @@ class MediaTttChipControllerReceiver @Inject constructor(
chipInfo.appNameOverride
)
}
+
+ override fun getIconSize(isAppIcon: Boolean): Int? =
+ context.resources.getDimensionPixelSize(
+ if (isAppIcon) {
+ R.dimen.media_ttt_icon_size_receiver
+ } else {
+ R.dimen.media_ttt_generic_icon_size_receiver
+ }
+ )
}
data class ChipReceiverInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
index 8bad2de189c5..2cc3986c6e82 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
@@ -21,6 +21,7 @@ import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.TextUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -158,22 +159,47 @@ public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.Intern
final int security = wifiEntry.getSecurity();
updateEndIcon(connectedState, security);
+ mWifiListLayout.setEnabled(shouldEnabled(wifiEntry));
if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) {
mWifiListLayout.setOnClickListener(
- v -> mInternetDialogController.launchWifiNetworkDetailsSetting(
+ v -> mInternetDialogController.launchWifiDetailsSetting(
wifiEntry.getKey(), v));
return;
}
- mWifiListLayout.setOnClickListener(v -> {
- if (wifiEntry.shouldEditBeforeConnect()) {
- final Intent intent = WifiUtils.getWifiDialogIntent(wifiEntry.getKey(),
- true /* connectForCaller */);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
- mContext.startActivity(intent);
- }
+ mWifiListLayout.setOnClickListener(v -> onWifiClick(wifiEntry, v));
+ }
+
+ boolean shouldEnabled(@NonNull WifiEntry wifiEntry) {
+ if (wifiEntry.canConnect()) {
+ return true;
+ }
+ // If Wi-Fi is connected or saved network, leave it enabled to disconnect or configure.
+ if (wifiEntry.canDisconnect() || wifiEntry.isSaved()) {
+ return true;
+ }
+ return false;
+ }
+
+ void onWifiClick(@NonNull WifiEntry wifiEntry, @NonNull View view) {
+ if (wifiEntry.shouldEditBeforeConnect()) {
+ final Intent intent = WifiUtils.getWifiDialogIntent(wifiEntry.getKey(),
+ true /* connectForCaller */);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+ mContext.startActivity(intent);
+ return;
+ }
+
+ if (wifiEntry.canConnect()) {
mInternetDialogController.connect(wifiEntry);
- });
+ return;
+ }
+
+ if (wifiEntry.isSaved()) {
+ Log.w(TAG, "The saved Wi-Fi network does not allow to connect. SSID:"
+ + wifiEntry.getSsid());
+ mInternetDialogController.launchWifiDetailsSetting(wifiEntry.getKey(), view);
+ }
}
void setWifiNetworkLayout(CharSequence title, CharSequence summary) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index d1c784457c9f..8921e95fcee9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -531,8 +531,7 @@ public class InternetDialog extends SystemUIDialog implements
if (mConnectedWifiEntry == null) {
return;
}
- mInternetDialogController.launchWifiNetworkDetailsSetting(mConnectedWifiEntry.getKey(),
- view);
+ mInternetDialogController.launchWifiDetailsSetting(mConnectedWifiEntry.getKey(), view);
}
void onClickSeeMoreButton(View view) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index b322cbf6c60e..d97ce7757d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -635,7 +635,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi
startActivity(getSettingsIntent(), view);
}
- void launchWifiNetworkDetailsSetting(String key, View view) {
+ void launchWifiDetailsSetting(String key, View view) {
Intent intent = getWifiDetailsSettingsIntent(key);
if (intent != null) {
startActivity(intent, view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index ade95a8cbfe7..c89f4d797819 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -217,6 +217,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private HashSet<View> mFromMoreCardAdditions = new HashSet<>();
private ArrayList<AnimationEvent> mAnimationEvents = new ArrayList<>();
private ArrayList<View> mSwipedOutViews = new ArrayList<>();
+ private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
private boolean mAnimationsEnabled;
private boolean mChangePositionInProgress;
@@ -415,6 +416,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private NotificationShelf mShelf;
private int mMaxDisplayedNotifications = -1;
private float mKeyguardBottomPadding = -1;
+ private float mKeyguardNotificationAvailableSpace = -1;
@VisibleForTesting int mStatusBarHeight;
private int mMinInteractionHeight;
private final Rect mClipRect = new Rect();
@@ -757,31 +759,34 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
} else {
mDebugTextUsedYPositions.clear();
}
- int y = mTopPadding;
- drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding = "+y);
+ int y = 0;
+ drawDebugInfo(canvas, y, Color.RED, /* label= */ "y = " + y);
+
+ y = mTopPadding;
+ drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding = " + y);
y = getLayoutHeight();
- drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight() = "+y);
+ drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight() = " + y);
y = (int) mMaxLayoutHeight;
- drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight = "+y);
+ drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight = " + y);
if (mKeyguardBottomPadding >= 0) {
y = getHeight() - (int) mKeyguardBottomPadding;
drawDebugInfo(canvas, y, Color.GRAY,
- /* label= */ "getHeight() - mKeyguardBottomPadding = "+y);
+ /* label= */ "getHeight() - mKeyguardBottomPadding = " + y);
}
y = getHeight() - getEmptyBottomMargin();
drawDebugInfo(canvas, y, Color.GREEN,
- /* label= */ "getHeight() - getEmptyBottomMargin() = "+y);
+ /* label= */ "getHeight() - getEmptyBottomMargin() = " + y);
y = (int) (mAmbientState.getStackY());
- drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY() = "+y);
+ drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY() = " + y);
y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
drawDebugInfo(canvas, y, Color.BLUE,
- /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight() = "+y);
+ /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight() = " + y);
y = (int) mAmbientState.getStackY() + mContentHeight;
drawDebugInfo(canvas, y, Color.MAGENTA,
@@ -790,6 +795,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
y = (int) mAmbientState.getStackY() + mIntrinsicContentHeight;
drawDebugInfo(canvas, y, Color.YELLOW,
/* label= */ "mAmbientState.getStackY() + mIntrinsicContentHeight = " + y);
+
+ y = (int) (mAmbientState.getStackY() + mKeyguardNotificationAvailableSpace);
+ drawDebugInfo(canvas, y, Color.RED, /* label= */
+ "mAmbientState.getStackY() + mKeyguardNotificationAvailableSpace = " + y);
}
private void drawDebugInfo(Canvas canvas, int y, int color, String label) {
@@ -956,13 +965,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
private void reinitView() {
- initView(getContext(), mSwipeHelper);
+ initView(getContext(), mSwipeHelper, mNotificationStackSizeCalculator);
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void initView(Context context, NotificationSwipeHelper swipeHelper) {
+ void initView(Context context, NotificationSwipeHelper swipeHelper,
+ NotificationStackSizeCalculator notificationStackSizeCalculator) {
mScroller = new OverScroller(getContext());
mSwipeHelper = swipeHelper;
+ mNotificationStackSizeCalculator = notificationStackSizeCalculator;
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setClipChildren(false);
@@ -2248,48 +2259,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateContentHeight() {
final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mMinimumPaddings;
- int height = (int) scrimTopPadding;
- float previousPaddingRequest = mPaddingBetweenElements;
- int numShownItems = 0;
- int numShownNotifs = 0;
- boolean finish = false;
- int maxDisplayedNotifications = mMaxDisplayedNotifications;
- ExpandableView previousView = null;
-
- for (int i = 0; i < getChildCount(); i++) {
- ExpandableView expandableView = (ExpandableView) getChildAt(i);
- boolean footerViewOnLockScreen = expandableView == mFooterView && onKeyguard();
-
- if (expandableView.getVisibility() != View.GONE
- && !expandableView.hasNoContentHeight() && !footerViewOnLockScreen) {
-
- boolean limitReached = maxDisplayedNotifications != -1
- && numShownNotifs >= maxDisplayedNotifications;
- final float viewHeight;
- if (limitReached) {
- viewHeight = mShelf.getIntrinsicHeight();
- finish = true;
- } else {
- viewHeight = expandableView.getIntrinsicHeight();
- }
- if (height != 0) {
- height += mPaddingBetweenElements;
- }
- float gapHeight = calculateGapHeight(previousView, expandableView, numShownNotifs);
- height += gapHeight;
- height += viewHeight;
-
- numShownItems++;
- if (viewHeight > 0 || !(expandableView instanceof MediaContainerView)) {
- // Only count the media as a notification if it has a positive height.
- numShownNotifs++;
- }
- previousView = expandableView;
- if (finish) {
- break;
- }
- }
- }
+ final int height =
+ (int) scrimTopPadding + (int) mNotificationStackSizeCalculator.computeHeight(
+ /* notificationStackScrollLayout= */ this, mMaxDisplayedNotifications,
+ mShelf != null ? mShelf.getIntrinsicHeight() : 0);
mIntrinsicContentHeight = height;
// The topPadding can be bigger than the regular padding when qs is expanded, in that
@@ -4932,6 +4905,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mKeyguardBottomPadding = keyguardBottomPadding;
}
+ /**
+ * For debugging only. Enables to draw a line related to the available size for notifications in
+ * keyguard.
+ */
+ public void setKeyguardAvailableSpaceForDebug(float keyguardNotificationAvailableSpace) {
+ mKeyguardNotificationAvailableSpace = keyguardNotificationAvailableSpace;
+ }
+
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) {
mShouldShowShelfOnly = shouldShowShelfOnly;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 6bbecc8438bc..d98f8a77cc8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -181,6 +181,7 @@ public class NotificationStackScrollLayoutController {
private final SectionHeaderController mSilentHeaderController;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final InteractionJankMonitor mJankMonitor;
+ private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private final StackStateLogger mStackStateLogger;
private final NotificationStackScrollLogger mLogger;
@@ -307,6 +308,7 @@ public class NotificationStackScrollLayoutController {
R.dimen.lockscreen_shade_notification_movement);
mTotalDistanceForFullShadeTransition = mResources.getDimensionPixelSize(
R.dimen.lockscreen_shade_qs_transition_distance);
+ mNotificationStackSizeCalculator.updateResources();
}
private final StatusBarStateController.StateListener mStateListener =
@@ -662,7 +664,8 @@ public class NotificationStackScrollLayoutController {
ShadeController shadeController,
InteractionJankMonitor jankMonitor,
StackStateLogger stackLogger,
- NotificationStackScrollLogger logger) {
+ NotificationStackScrollLogger logger,
+ NotificationStackSizeCalculator notificationStackSizeCalculator) {
mStackStateLogger = stackLogger;
mLogger = logger;
mAllowLongPress = allowLongPress;
@@ -688,6 +691,7 @@ public class NotificationStackScrollLayoutController {
mCentralSurfaces = centralSurfaces;
mScrimController = scrimController;
mJankMonitor = jankMonitor;
+ mNotificationStackSizeCalculator = notificationStackSizeCalculator;
groupManager.registerGroupExpansionChangeListener(
(changedRow, expanded) -> mView.onGroupExpandChanged(changedRow, expanded));
legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() {
@@ -758,7 +762,7 @@ public class NotificationStackScrollLayoutController {
});
}
- mView.initView(mView.getContext(), mSwipeHelper);
+ mView.initView(mView.getContext(), mSwipeHelper, mNotificationStackSizeCalculator);
mView.setKeyguardBypassEnabled(mKeyguardBypassController.getBypassEnabled());
mKeyguardBypassController
.registerOnBypassStateChangedListener(mView::setKeyguardBypassEnabled);
@@ -907,6 +911,13 @@ public class NotificationStackScrollLayoutController {
return mView.getTop();
}
+ /**
+ * @return the bottom of the view.
+ */
+ public int getBottom() {
+ return mView.getBottom();
+ }
+
public float getTranslationX() {
return mView.getTranslationX();
}
@@ -1296,10 +1307,16 @@ public class NotificationStackScrollLayoutController {
* appear on the keyguard.
* Setting a negative number will disable rendering this line.
*/
- public void setKeyguardBottomPadding(float keyguardBottomPadding) {
+ public void setKeyguardBottomPaddingForDebug(float keyguardBottomPadding) {
mView.setKeyguardBottomPadding(keyguardBottomPadding);
}
+ /** For debugging only. */
+ public void mKeyguardNotificationAvailableSpaceForDebug(
+ float keyguardNotificationAvailableSpace) {
+ mView.setKeyguardAvailableSpaceForDebug(keyguardNotificationAvailableSpace);
+ }
+
public RemoteInputController.Delegate createDelegate() {
return new RemoteInputController.Delegate() {
public void setRemoteInputActive(NotificationEntry entry,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
new file mode 100644
index 000000000000..3f97155242b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2022 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.statusbar.notification.stack
+
+import android.content.res.Resources
+import android.util.Log
+import android.view.View.GONE
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.util.children
+import javax.inject.Inject
+import kotlin.math.max
+import kotlin.properties.Delegates.notNull
+
+private const val TAG = "NotificationStackSizeCalculator"
+private const val DEBUG = false
+
+/** Calculates number of notifications to display and the height of the notification stack. */
+@SysUISingleton
+class NotificationStackSizeCalculator
+@Inject
+constructor(
+ private val groupManager: NotificationGroupManagerLegacy,
+ private val lockscreenUserManager: NotificationLockscreenUserManager,
+ private val statusBarStateController: SysuiStatusBarStateController,
+ @Main private val resources: Resources
+) {
+
+ /**
+ * Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow shelf.
+ * If there are exactly 1 + mMaxKeyguardNotifications, and they fit in the available space
+ * (considering the overflow shelf is not displayed in this case), then all notifications are
+ * shown.
+ */
+ private var maxKeyguardNotifications by notNull<Int>()
+
+ /**
+ * Minimum space between two notifications. There might be more space, see [calculateGapHeight].
+ */
+ private var notificationPadding by notNull<Int>()
+
+ init {
+ updateResources()
+ }
+
+ /**
+ * Given the [availableSpace] constraint, calculates how many notification to show.
+ *
+ * This number is only valid in keyguard.
+ *
+ * @param availableSpace space for notifications. This doesn't include the space for the shelf.
+ */
+ fun computeMaxKeyguardNotifications(
+ stack: NotificationStackScrollLayout,
+ availableSpace: Float,
+ shelfHeight: Float
+ ): Int {
+ log {
+ "computeMaxKeyguardNotifications(" +
+ "availableSpace=$availableSpace shelfHeight=$shelfHeight)"
+ }
+
+ val children: Sequence<ExpandableView> = stack.childrenSequence
+ var remainingSpace: Float = availableSpace
+ var count = 0
+ var previous: ExpandableView? = null
+ val onLockscreen = true
+ val showableRows = children.filter { it.isShowable(onLockscreen) }
+ val showableRowsCount = showableRows.count()
+ showableRows.forEachIndexed { i, current ->
+ val spaceNeeded = current.spaceNeeded(count, previous, stack, onLockscreen)
+ previous = current
+ log { "\ti=$i spaceNeeded=$spaceNeeded remainingSpace=$remainingSpace" }
+
+ if (remainingSpace - spaceNeeded >= 0 && count < maxKeyguardNotifications) {
+ count += 1
+ remainingSpace -= spaceNeeded
+ } else if (remainingSpace - spaceNeeded > -shelfHeight && i == showableRowsCount - 1) {
+ log { "Showing all notifications. Shelf is not be needed." }
+ // If this is the last one, and it fits using the space shelf would use, then we can
+ // display it, as the shelf will not be needed (as all notifications are shown).
+ return count + 1
+ } else {
+ log {
+ "No more fit. Returning $count. Space used: ${availableSpace - remainingSpace}"
+ }
+ return count
+ }
+ }
+ log { "All fit. Returning $count" }
+ return count
+ }
+
+ /**
+ * Given the [maxNotifications] constraint, calculates the height of the
+ * [NotificationStackScrollLayout]. This might or might not be in keyguard.
+ *
+ * @param stack stack containing notifications as children.
+ * @param maxNotifications Maximum number of notifications. When reached, the others will go
+ * into the shelf.
+ * @param shelfHeight height of the shelf. It might be zero.
+ *
+ * @return height of the stack, including shelf height, if needed.
+ */
+ fun computeHeight(
+ stack: NotificationStackScrollLayout,
+ maxNotifications: Int,
+ shelfHeight: Float
+ ): Float {
+ val children: Sequence<ExpandableView> = stack.childrenSequence
+ val maxNotificationsArg = infiniteIfNegative(maxNotifications)
+ var height = 0f
+ var previous: ExpandableView? = null
+ var count = 0
+ val onLockscreen = onLockscreen()
+
+ log { "computeHeight(maxNotification=$maxNotifications, shelf=$shelfHeight" }
+ children.filter { it.isShowable(onLockscreen) }.forEach { current ->
+ if (count < maxNotificationsArg) {
+ val spaceNeeded = current.spaceNeeded(count, previous, stack, onLockscreen)
+ log { "\ti=$count spaceNeeded=$spaceNeeded" }
+ height += spaceNeeded
+ count += 1
+ } else {
+ height += shelfHeight
+ log { "returning height with shelf -> $height" }
+ return height
+ }
+ previous = current
+ }
+ log { "Returning height without shelf -> $height" }
+ return height
+ }
+
+ fun updateResources() {
+ maxKeyguardNotifications =
+ infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
+
+ notificationPadding =
+ max(1, resources.getDimensionPixelSize(R.dimen.notification_divider_height))
+ }
+
+ private val NotificationStackScrollLayout.childrenSequence: Sequence<ExpandableView>
+ get() = children.map { it as ExpandableView }
+
+ private fun onLockscreen() = statusBarStateController.state == KEYGUARD
+
+ private fun ExpandableView.spaceNeeded(
+ visibleIndex: Int,
+ previousView: ExpandableView?,
+ stack: NotificationStackScrollLayout,
+ onLockscreen: Boolean
+ ): Float {
+ assert(isShowable(onLockscreen))
+ var size =
+ if (onLockscreen) {
+ getMinHeight(/* ignoreTemporaryStates= */ true).toFloat()
+ } else {
+ intrinsicHeight.toFloat()
+ }
+ if (visibleIndex != 0) {
+ size += notificationPadding
+ }
+ size += calculateGapHeight(stack, previousView, visibleIndex)
+ return size
+ }
+
+ private fun ExpandableView.isShowable(onLockscreen: Boolean): Boolean {
+ if (visibility == GONE || hasNoContentHeight()) return false
+ if (onLockscreen) {
+ when (this) {
+ is ExpandableNotificationRow -> {
+ if (isSummaryOfSuppressedGroup() || !canShowViewOnLockscreen() || isRemoved) {
+ return false
+ }
+ }
+ is MediaContainerView -> if (intrinsicHeight == 0) return false
+ else -> return false
+ }
+ }
+ return true
+ }
+
+ private fun ExpandableView.calculateGapHeight(
+ stack: NotificationStackScrollLayout,
+ previous: ExpandableView?,
+ visibleIndex: Int
+ ) = stack.calculateGapHeight(previous, /* current= */ this, visibleIndex)
+
+ private fun ExpandableNotificationRow.isSummaryOfSuppressedGroup() =
+ groupManager.isSummaryOfSuppressedGroup(entry.sbn)
+
+ /**
+ * Can a view be shown on the lockscreen when calculating the number of allowed notifications to
+ * show?
+ *
+ * @return `true` if it can be shown.
+ */
+ private fun ExpandableView.canShowViewOnLockscreen(): Boolean {
+ if (hasNoContentHeight()) {
+ return false
+ }
+ if (this is ExpandableNotificationRow && !canShowRowOnLockscreen()) {
+ return false
+ } else if (visibility == GONE) {
+ return false
+ }
+ return true
+ }
+
+ /**
+ * Can a row be shown on the lockscreen when calculating the number of allowed notifications to
+ * show?
+ *
+ * @return true if it can be shown
+ */
+ private fun ExpandableNotificationRow.canShowRowOnLockscreen(): Boolean {
+ if (isSummaryOfSuppressedGroup()) {
+ return false
+ }
+ if (!lockscreenUserManager.shouldShowOnKeyguard(entry)) {
+ return false
+ }
+ return !isRemoved
+ }
+
+ private fun log(s: () -> String) {
+ if (DEBUG) {
+ Log.d(TAG, s())
+ }
+ }
+
+ /** Returns infinite when [v] is negative. Useful in case a resource doesn't limit when -1. */
+ private fun infiniteIfNegative(v: Int): Int =
+ if (v < 0) {
+ Int.MAX_VALUE
+ } else {
+ v
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 732e5f0343a2..602d075b167d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -23,6 +23,7 @@ import static com.android.systemui.statusbar.notification.NotificationUtils.inte
import android.content.res.Resources;
import android.util.MathUtils;
+import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
@@ -169,7 +170,8 @@ public class KeyguardClockPositionAlgorithm {
boolean isSplitShade, float udfpsTop, float clockBottom, boolean isClockTopAligned) {
mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
userSwitchHeight);
- mPanelExpansion = panelExpansion;
+ mPanelExpansion = BouncerPanelExpansionCalculator
+ .getKeyguardClockScaledExpansion(panelExpansion);
mKeyguardStatusHeight = keyguardStatusHeight + mStatusViewBottomMargin;
mUserSwitchHeight = userSwitchHeight;
mUserSwitchPreferredY = userSwitchPreferredY;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index 571c10b3800f..64b0b4e2909f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -16,34 +16,52 @@
package com.android.systemui.statusbar.phone
+import android.content.Context
+import android.content.pm.PackageManager
import android.hardware.Sensor
import android.hardware.TriggerEvent
import android.hardware.TriggerEventListener
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.CoreStartable
import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.util.Assert
import com.android.systemui.util.sensors.AsyncSensorManager
import java.io.FileDescriptor
import java.io.PrintWriter
+import javax.inject.Inject
-class KeyguardLiftController constructor(
+/**
+ * Triggers face auth on lift when the device is showing the lock screen. Only initialized
+ * if face auth is supported on the device. Not to be confused with the lift to wake gesture
+ * which is handled by {@link com.android.server.policy.PhoneWindowManager}.
+ */
+@SysUISingleton
+class KeyguardLiftController @Inject constructor(
+ private val context: Context,
private val statusBarStateController: StatusBarStateController,
private val asyncSensorManager: AsyncSensorManager,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- dumpManager: DumpManager
-) : StatusBarStateController.StateListener, Dumpable, KeyguardUpdateMonitorCallback() {
+ private val dumpManager: DumpManager
+) : Dumpable, CoreStartable(context) {
private val pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)
private var isListening = false
private var bouncerVisible = false
- init {
+ override fun start() {
+ if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ init()
+ }
+ }
+
+ private fun init() {
dumpManager.registerDumpable(javaClass.name, this)
- statusBarStateController.addCallback(this)
- keyguardUpdateMonitor.registerCallback(this)
+ statusBarStateController.addCallback(statusBarStateListener)
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
updateListeningState()
}
@@ -58,17 +76,21 @@ class KeyguardLiftController constructor(
}
}
- override fun onDozingChanged(isDozing: Boolean) {
- updateListeningState()
- }
+ private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
+ override fun onKeyguardBouncerChanged(bouncer: Boolean) {
+ bouncerVisible = bouncer
+ updateListeningState()
+ }
- override fun onKeyguardBouncerChanged(bouncer: Boolean) {
- bouncerVisible = bouncer
- updateListeningState()
+ override fun onKeyguardVisibilityChanged(showing: Boolean) {
+ updateListeningState()
+ }
}
- override fun onKeyguardVisibilityChanged(showing: Boolean) {
- updateListeningState()
+ private val statusBarStateListener = object : StatusBarStateController.StateListener {
+ override fun onDozingChanged(isDozing: Boolean) {
+ updateListeningState()
+ }
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index af4fb8e2cf49..a70ba8236e9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -58,7 +58,6 @@ import com.android.systemui.util.ViewController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
@@ -289,10 +288,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
);
Resources r = getResources();
- mBlockedIcons = Collections.unmodifiableList(Arrays.asList(
- r.getString(com.android.internal.R.string.status_bar_volume),
- r.getString(com.android.internal.R.string.status_bar_alarm_clock),
- r.getString(com.android.internal.R.string.status_bar_call_strength)));
+ mBlockedIcons = Arrays.asList(r.getStringArray(
+ R.array.config_keyguard_statusbar_icon_blocklist));
mNotificationsHeaderCollideDistance = r.getDimensionPixelSize(
R.dimen.header_notifications_collide_distance);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 1891ab017ef8..5746ffb6debe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static android.view.View.GONE;
import static androidx.constraintlayout.widget.ConstraintSet.END;
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
@@ -144,7 +143,6 @@ import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -165,17 +163,16 @@ import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.render.ShadeViewManager;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
-import com.android.systemui.statusbar.notification.stack.MediaContainerView;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
@@ -312,9 +309,6 @@ public class NotificationPanelViewController extends PanelViewController {
private final ControlsComponent mControlsComponent;
private final NotificationRemoteInputManager mRemoteInputManager;
- // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
- // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
- private final int mMaxKeyguardNotifications;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final TapAgainViewController mTapAgainViewController;
private final SplitShadeHeaderController mSplitShadeHeaderController;
@@ -323,6 +317,8 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mShouldUseSplitNotificationShade;
// The bottom padding reserved for elements of the keyguard measuring notifications
private float mKeyguardNotificationBottomPadding;
+ // Space available for notifications.
+ private float mKeyguardNotificationAvailableSpace;
// Current max allowed keyguard notifications determined by measuring the panel
private int mMaxAllowedKeyguardNotifications;
@@ -446,8 +442,6 @@ public class NotificationPanelViewController extends PanelViewController {
setHeadsUpAnimatingAway(false);
updatePanelExpansionAndVisibility();
};
- // TODO (b/162832756): once migrated to the new pipeline, delete legacy group manager
- private NotificationGroupManagerLegacy mGroupManager;
private boolean mShowIconsWhenExpanded;
private int mIndicationBottomPadding;
private int mAmbientIndicationBottomPadding;
@@ -509,7 +503,6 @@ public class NotificationPanelViewController extends PanelViewController {
private final NotificationEntryManager mEntryManager;
private final CommandQueue mCommandQueue;
- private final NotificationLockscreenUserManager mLockscreenUserManager;
private final UserManager mUserManager;
private final MediaDataManager mMediaDataManager;
private final SysUiState mSysUiState;
@@ -651,6 +644,7 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationPanelUnfoldAnimationController;
private final NotificationListContainer mNotificationListContainer;
+ private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
@Override
@@ -695,7 +689,6 @@ public class NotificationPanelViewController extends PanelViewController {
DynamicPrivacyController dynamicPrivacyController,
KeyguardBypassController bypassController, FalsingManager falsingManager,
FalsingCollector falsingCollector,
- NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationEntryManager notificationEntryManager,
KeyguardStateController keyguardStateController,
StatusBarStateController statusBarStateController,
@@ -721,7 +714,6 @@ public class NotificationPanelViewController extends PanelViewController {
KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory,
KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
- NotificationGroupManagerLegacy groupManager,
NotificationIconAreaController notificationIconAreaController,
AuthController authController,
ScrimController scrimController,
@@ -753,7 +745,8 @@ public class NotificationPanelViewController extends PanelViewController {
SysUiState sysUiState,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
NotificationListContainer notificationListContainer,
- PanelEventsEmitter panelEventsEmitter) {
+ PanelEventsEmitter panelEventsEmitter,
+ NotificationStackSizeCalculator notificationStackSizeCalculator) {
super(view,
falsingManager,
dozeLog,
@@ -785,9 +778,9 @@ public class NotificationPanelViewController extends PanelViewController {
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mNotificationsQSContainerController = notificationsQSContainerController;
mNotificationListContainer = notificationListContainer;
+ mNotificationStackSizeCalculator = notificationStackSizeCalculator;
mNotificationsQSContainerController.init();
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
- mGroupManager = groupManager;
mNotificationIconAreaController = notificationIconAreaController;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
@@ -849,7 +842,6 @@ public class NotificationPanelViewController extends PanelViewController {
});
mBottomAreaShadeAlphaAnimator.setDuration(160);
mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
- mLockscreenUserManager = notificationLockscreenUserManager;
mEntryManager = notificationEntryManager;
mConversationNotificationManager = conversationNotificationManager;
mAuthController = authController;
@@ -874,7 +866,6 @@ public class NotificationPanelViewController extends PanelViewController {
mView.getOverlay().add(new DebugDrawable());
}
- mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
mKeyguardUnfoldTransition = unfoldComponent.map(c -> c.getKeyguardUnfoldTransition());
mNotificationPanelUnfoldAnimationController = unfoldComponent.map(
SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController);
@@ -1238,12 +1229,14 @@ public class NotificationPanelViewController extends PanelViewController {
if (mKeyguardShowing && !mKeyguardBypassController.getBypassEnabled()) {
mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(
mMaxAllowedKeyguardNotifications);
- mNotificationStackScrollLayoutController.setKeyguardBottomPadding(
+ mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug(
mKeyguardNotificationBottomPadding);
+ mNotificationStackScrollLayoutController.mKeyguardNotificationAvailableSpaceForDebug(
+ mKeyguardNotificationAvailableSpace);
} else {
// no max when not on the keyguard
mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(-1);
- mNotificationStackScrollLayoutController.setKeyguardBottomPadding(-1f);
+ mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug(-1f);
}
}
@@ -1454,127 +1447,38 @@ public class NotificationPanelViewController extends PanelViewController {
* @return the maximum keyguard notifications that can fit on the screen
*/
private int computeMaxKeyguardNotifications() {
- float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding();
int notificationPadding = Math.max(
1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height));
- float shelfSize =
+ float topPadding = mNotificationStackScrollLayoutController.getTopPadding();
+ float shelfHeight =
mNotificationShelfController.getVisibility() == View.GONE
? 0
: mNotificationShelfController.getIntrinsicHeight() + notificationPadding;
+ // Padding to add to the bottom of the stack to keep a minimum distance from the top of
+ // the lock icon.
float lockIconPadding = 0;
if (mLockIconViewController.getTop() != 0) {
- lockIconPadding = mCentralSurfaces.getDisplayHeight() - mLockIconViewController.getTop()
- + mResources.getDimensionPixelSize(R.dimen.min_lock_icon_padding);
+ final float lockIconTopWithPadding = mLockIconViewController.getTop()
+ - mResources.getDimensionPixelSize(R.dimen.min_lock_icon_padding);
+ lockIconPadding = mNotificationStackScrollLayoutController.getBottom()
+ - lockIconTopWithPadding;
}
- float bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
- bottomPadding = Math.max(lockIconPadding, bottomPadding);
+ float bottomPadding = Math.max(lockIconPadding,
+ Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding));
mKeyguardNotificationBottomPadding = bottomPadding;
float availableSpace =
mNotificationStackScrollLayoutController.getHeight()
- - minPadding
- - shelfSize
+ - topPadding
+ - shelfHeight
- bottomPadding;
+ mKeyguardNotificationAvailableSpace = availableSpace;
- int count = 0;
- ExpandableView previousView = null;
- for (int i = 0; i < mNotificationStackScrollLayoutController.getChildCount(); i++) {
- ExpandableView child = mNotificationStackScrollLayoutController.getChildAt(i);
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- boolean suppressedSummary = mGroupManager != null
- && mGroupManager.isSummaryOfSuppressedGroup(row.getEntry().getSbn());
- if (suppressedSummary) {
- continue;
- }
- if (!canShowViewOnLockscreen(child)) {
- continue;
- }
- if (row.isRemoved()) {
- continue;
- }
- } else if (child instanceof MediaContainerView) {
- if (child.getVisibility() == GONE) {
- continue;
- }
- if (child.getIntrinsicHeight() == 0) {
- continue;
- }
- } else {
- continue;
- }
- availableSpace -= child.getMinHeight(true /* ignoreTemporaryStates */);
- availableSpace -= count == 0 ? 0 : notificationPadding;
- availableSpace -= mNotificationStackScrollLayoutController
- .calculateGapHeight(previousView, child, count);
- previousView = child;
- if (availableSpace >= 0
- && (mMaxKeyguardNotifications == -1 || count < mMaxKeyguardNotifications)) {
- count++;
- } else if (availableSpace > -shelfSize) {
- // if we are exactly the last view, then we can show us still!
- int childCount = mNotificationStackScrollLayoutController.getChildCount();
- for (int j = i + 1; j < childCount; j++) {
- ExpandableView view = mNotificationStackScrollLayoutController.getChildAt(j);
- if (view instanceof ExpandableNotificationRow
- && canShowViewOnLockscreen(view)) {
- return count;
- }
- }
- count++;
- return count;
- } else {
- return count;
- }
- }
- return count;
- }
-
- /**
- * Can a view be shown on the lockscreen when calculating the number of allowed notifications
- * to show?
- *
- * @param child the view in question
- * @return true if it can be shown
- */
- private boolean canShowViewOnLockscreen(ExpandableView child) {
- if (child.hasNoContentHeight()) {
- return false;
- }
- if (child instanceof ExpandableNotificationRow &&
- !canShowRowOnLockscreen((ExpandableNotificationRow) child)) {
- return false;
- } else if (child.getVisibility() == GONE) {
- // ENRs can be gone and count because their visibility is only set after
- // this calculation, but all other views should be up to date
- return false;
- }
- return true;
- }
-
- /**
- * Can a row be shown on the lockscreen when calculating the number of allowed notifications
- * to show?
- *
- * @param row the row in question
- * @return true if it can be shown
- */
- private boolean canShowRowOnLockscreen(ExpandableNotificationRow row) {
- boolean suppressedSummary =
- mGroupManager != null && mGroupManager.isSummaryOfSuppressedGroup(
- row.getEntry().getSbn());
- if (suppressedSummary) {
- return false;
- }
- if (!mLockscreenUserManager.shouldShowOnKeyguard(row.getEntry())) {
- return false;
- }
- if (row.isRemoved()) {
- return false;
- }
- return true;
+ return mNotificationStackSizeCalculator.computeMaxKeyguardNotifications(
+ mNotificationStackScrollLayoutController.getView(), availableSpace,
+ shelfHeight);
}
private void updateClock() {
@@ -4883,6 +4787,8 @@ public class NotificationPanelViewController extends PanelViewController {
"calculateNotificationsTopPadding()");
drawDebugInfo(canvas, mClockPositionResult.clockY, Color.GRAY,
"mClockPositionResult.clockY");
+ drawDebugInfo(canvas, (int) mLockIconViewController.getTop(), Color.GRAY,
+ "mLockIconViewController.getTop()");
mDebugPaint.setColor(Color.CYAN);
canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, mView.getWidth(),
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 1ad365bf6d7b..029a7a5fcdd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -41,6 +41,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.function.TriConsumer;
+import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.Utils;
@@ -808,7 +809,15 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private Pair<Integer, Float> calculateBackStateForState(ScrimState state) {
// Either darken of make the scrim transparent when you
// pull down the shade
- float interpolatedFract = getInterpolatedFraction();
+ float interpolatedFract;
+
+ if (state == ScrimState.KEYGUARD) {
+ interpolatedFract = BouncerPanelExpansionCalculator
+ .getBackScrimScaledExpansion(mPanelExpansionFraction);
+ } else {
+ interpolatedFract = getInterpolatedFraction();
+ }
+
float stateBehind = mClipsQsScrim ? state.getNotifAlpha() : state.getBehindAlpha();
float behindAlpha;
int behindTint;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 33bc40119745..8194957c52fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -72,6 +72,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
@@ -217,11 +218,23 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
void updateBlockedIcons() {
mBlockedIcons.clear();
- if (mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) == 0) {
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume));
+ // Reload the blocklist from res
+ List<String> blockList = Arrays.asList(getResources().getStringArray(
+ R.array.config_collapsed_statusbar_icon_blocklist));
+ String vibrateIconSlot = getString(com.android.internal.R.string.status_bar_volume);
+ boolean showVibrateIcon =
+ mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) == 0;
+
+ // Filter out vibrate icon from the blocklist if the setting is on
+ for (int i = 0; i < blockList.size(); i++) {
+ if (blockList.get(i).equals(vibrateIconSlot)) {
+ if (showVibrateIcon) {
+ mBlockedIcons.add(blockList.get(i));
+ }
+ } else {
+ mBlockedIcons.add(blockList.get(i));
+ }
}
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock));
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength));
mMainExecutor.execute(() -> mDarkIconManager.setBlockList(mBlockedIcons));
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index c0d7925cf2bb..9e9b74616d29 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -23,7 +23,6 @@ import android.content.IntentFilter
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
-import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.LayerDrawable
import android.os.Bundle
import android.os.UserManager
@@ -149,8 +148,8 @@ class UserSwitcherActivity @Inject constructor(
}
private fun getDrawable(item: UserRecord): Drawable {
- var drawable = if (item.isCurrent && item.isGuest) {
- getDrawable(R.drawable.ic_avatar_guest_user)
+ var drawable = if (item.isGuest) {
+ getDrawable(R.drawable.ic_account_circle)
} else {
findUserIcon(item)
}
@@ -168,7 +167,7 @@ class UserSwitcherActivity @Inject constructor(
val ld = getDrawable(R.drawable.user_switcher_icon_large).mutate()
as LayerDrawable
if (item == userSwitcherController.getCurrentUserRecord()) {
- (ld.getDrawable(1) as GradientDrawable).apply {
+ (ld.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
val stroke = resources
.getDimensionPixelSize(R.dimen.user_switcher_icon_selected_width)
val color = Utils.getColorAttrDefaultColor(
@@ -180,15 +179,7 @@ class UserSwitcherActivity @Inject constructor(
}
}
- ld.addLayer(
- InsetDrawable(
- drawable,
- resources.getDimensionPixelSize(
- R.dimen.user_switcher_icon_large_margin
- )
- )
- )
-
+ ld.setDrawableByLayerId(R.id.user_avatar, drawable)
return ld
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
new file mode 100644
index 000000000000..6266bf146f5b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 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.keyguard
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class BouncerPanelExpansionCalculatorTest : SysuiTestCase() {
+ @Test
+ fun testGetHostViewScaledExpansion() {
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(1f))
+ .isEqualTo(1f)
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0.9f))
+ .isEqualTo(1f)
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0.59f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0f))
+ .isEqualTo(0f)
+ assertEquals(BouncerPanelExpansionCalculator
+ .getHostViewScaledExpansion(0.8f), 2f / 3f, 0.01f)
+ }
+
+ @Test
+ fun testGetBackScrimScaledExpansion() {
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(1f))
+ .isEqualTo(1f)
+ assertEquals(BouncerPanelExpansionCalculator
+ .getBackScrimScaledExpansion(0.95f), 1f / 2f, 0.01f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.9f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.5f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0f))
+ .isEqualTo(0f)
+ }
+
+ @Test
+ fun testGetKeyguardClockScaledExpansion() {
+ assertThat(BouncerPanelExpansionCalculator.getKeyguardClockScaledExpansion(1f))
+ .isEqualTo(1f)
+ assertEquals(BouncerPanelExpansionCalculator
+ .getKeyguardClockScaledExpansion(0.8f), 1f / 3f, 0.01f)
+ assertThat(BouncerPanelExpansionCalculator.getKeyguardClockScaledExpansion(0.7f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.5f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0f))
+ .isEqualTo(0f)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index ef82c3ec3322..fd49766dafef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -61,6 +61,8 @@ import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+private const val REQUEST_ID = 2L
+
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
@@ -119,7 +121,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
statusBarStateController, panelExpansionStateManager, statusBarKeyguardViewManager,
keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
configurationController, systemClock, keyguardStateController,
- unlockedScreenOffAnimationController, sensorProps, hbmProvider, reason,
+ unlockedScreenOffAnimationController, sensorProps, hbmProvider, REQUEST_ID, reason,
controllerCallback, onTouch, activityLaunchAnimator)
block()
}
@@ -263,6 +265,12 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
controllerOverlay.hide()
verify(udfpsView).stopIllumination()
}
+
+ @Test
+ fun matchesRequestIds() = withReason(REASON_AUTH_BP) {
+ assertThat(controllerOverlay.matchesRequestId(REQUEST_ID)).isTrue()
+ assertThat(controllerOverlay.matchesRequestId(REQUEST_ID + 1)).isFalse()
+ }
}
private class EnrollListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 613931f1341f..406ed5c17b0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -102,6 +103,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// Use this for inputs going into SystemUI. Use UdfpsController.mUdfpsSensorId for things
// leaving SystemUI.
private static final int TEST_UDFPS_SENSOR_ID = 1;
+ private static final long TEST_REQUEST_ID = 70;
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@@ -278,7 +280,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void dozeTimeTick() throws RemoteException {
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
mUdfpsController.dozeTimeTick();
@@ -293,7 +295,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -316,7 +318,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mStatusBarStateController.isDozing()).thenReturn(true);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -339,7 +341,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mStatusBarStateController.isDozing()).thenReturn(false);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -362,7 +364,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
(UdfpsAnimationViewController) mock(UdfpsEnrollViewController.class));
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -377,25 +379,42 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
- public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
+ public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice()
+ throws RemoteException {
+ onActionMoveTouch_whenCanDismissLockScreen_entersDevice(false /* stale */);
+ }
+
+ @Test
+ public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice_ignoreStale()
+ throws RemoteException {
+ onActionMoveTouch_whenCanDismissLockScreen_entersDevice(true /* stale */);
+ }
+
+ public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice(boolean stale)
+ throws RemoteException {
// GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// WHEN ACTION_MOVE is received
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ if (stale) {
+ mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+ mFgExecutor.runAllReady();
+ }
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
moveEvent.recycle();
// THEN notify keyguard authenticate to dismiss the keyguard
- verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ verify(mStatusBarKeyguardViewManager, stale ? never() : times(1))
+ .notifyKeyguardAuthenticated(anyBoolean());
}
@Test
@@ -406,7 +425,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -427,7 +446,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
// GIVEN overlay was showing and the udfps bouncer is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true);
@@ -441,7 +460,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -460,7 +479,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// WHEN ACTION_DOWN is received
@@ -472,8 +491,9 @@ public class UdfpsControllerTest extends SysuiTestCase {
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
moveEvent.recycle();
// THEN FingerprintManager is notified about onPointerDown
- verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
- eq(0), eq(0f), eq(0f));
+ verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+ eq(mUdfpsController.mSensorProps.sensorId),
+ eq(0), eq(0), eq(0f), eq(0f));
verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
// AND illumination begins
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
@@ -481,14 +501,15 @@ public class UdfpsControllerTest extends SysuiTestCase {
// AND onIlluminatedRunnable notifies FingerprintManager about onUiReady
mOnIlluminatedRunnableCaptor.getValue().run();
InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker);
- inOrder.verify(mFingerprintManager).onUiReady(eq(mUdfpsController.mSensorProps.sensorId));
+ inOrder.verify(mFingerprintManager).onUiReady(
+ eq(TEST_REQUEST_ID), eq(mUdfpsController.mSensorProps.sensorId));
inOrder.verify(mLatencyTracker).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
}
@Test
public void aodInterrupt() throws RemoteException {
// GIVEN that the overlay is showing and screen is on and fp is running
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -499,14 +520,15 @@ public class UdfpsControllerTest extends SysuiTestCase {
// AND onIlluminatedRunnable that notifies FingerprintManager is set
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
mOnIlluminatedRunnableCaptor.getValue().run();
- verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
- eq(0), eq(3f) /* minor */, eq(2f) /* major */);
+ verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+ eq(mUdfpsController.mSensorProps.sensorId),
+ eq(0), eq(0), eq(3f) /* minor */, eq(2f) /* major */);
}
@Test
public void cancelAodInterrupt() throws RemoteException {
// GIVEN AOD interrupt
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -522,7 +544,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterruptTimeout() throws RemoteException {
// GIVEN AOD interrupt
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -539,7 +561,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterruptScreenOff() throws RemoteException {
// GIVEN screen off
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOff();
mFgExecutor.runAllReady();
@@ -555,7 +577,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterrupt_fingerprintNotRunning() throws RemoteException {
// GIVEN showing overlay
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD,
mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
@@ -577,7 +599,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the overlay is showing and a11y touch exploration enabled
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -612,7 +634,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the overlay is showing and a11y touch exploration NOT enabled
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index a32ff801e824..a6921b441f17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -53,6 +53,8 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.concurrent.Executor;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
@@ -90,6 +92,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
@Mock
ZenModeController mZenModeController;
+ private final Executor mMainExecutor = Runnable::run;
+
DreamOverlayStatusBarViewController mController;
@Before
@@ -102,6 +106,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
mController = new DreamOverlayStatusBarViewController(
mView,
mResources,
+ mMainExecutor,
mConnectivityManager,
mTouchSession,
mAlarmManager,
@@ -134,7 +139,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
.thenReturn(false);
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
}
@Test
@@ -143,13 +149,16 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
.thenReturn(true);
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
}
@Test
public void testOnViewAttachedShowsWifiIconWhenNetworkCapabilitiesUnavailable() {
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(null);
mController.onViewAttached();
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
}
@Test
@@ -176,7 +185,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
.thenReturn(true);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
}
@Test
@@ -186,7 +196,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
.thenReturn(false);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false, null);
}
@Test
@@ -211,7 +222,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mZenModeController.getZen()).thenReturn(
Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
}
@Test
@@ -219,7 +231,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mZenModeController.getZen()).thenReturn(
Settings.Global.ZEN_MODE_OFF);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
}
@Test
@@ -250,7 +263,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture());
callbackCapture.getValue().onAvailable(mNetwork);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
}
@Test
@@ -266,7 +281,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture());
callbackCapture.getValue().onLost(mNetwork);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true);
+
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
}
@Test
@@ -283,7 +300,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
.thenReturn(true);
callbackCapture.getValue().onCapabilitiesChanged(mNetwork, mNetworkCapabilities);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
}
@Test
@@ -333,7 +352,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
callbackCapture.getValue().onSensorBlockedChanged(
SensorPrivacyManager.Sensors.MICROPHONE, true);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
}
@Test
@@ -350,7 +370,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
callbackCapture.getValue().onSensorBlockedChanged(
SensorPrivacyManager.Sensors.MICROPHONE, false);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false, null);
}
@Test
@@ -364,7 +385,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
verify(mZenModeController).addCallback(callbackCapture.capture());
callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
}
@Test
@@ -373,12 +395,12 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
.thenReturn(Settings.Global.ZEN_MODE_OFF);
mController.onViewAttached();
-
final ArgumentCaptor<ZenModeController.Callback> callbackCapture =
ArgumentCaptor.forClass(ZenModeController.Callback.class);
verify(mZenModeController).addCallback(callbackCapture.capture());
callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_OFF);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index dcbe0ab96dac..daf81bdc6e82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -37,7 +37,6 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import javax.inject.Provider
-import org.mockito.Mockito.`when` as whenever
private val DATA = MediaData(
userId = -1,
@@ -83,7 +82,6 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
mediaCarouselController = MediaCarouselController(
context,
mediaControlPanelFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index cb68d81287df..90eff1ae9804 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -101,7 +101,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory
@Mock private lateinit var mediaCarouselController: MediaCarouselController
@Mock private lateinit var falsingManager: FalsingManager
- @Mock private lateinit var mediaFlags: MediaFlags
private lateinit var appIcon: ImageView
private lateinit var albumView: ImageView
private lateinit var titleText: TextView
@@ -147,7 +146,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
player = MediaControlPanel(context, bgExecutor, activityStarter, broadcastSender,
mediaViewController, seekBarViewModel, Lazy { mediaDataManager },
- mediaOutputDialogFactory, mediaCarouselController, falsingManager, mediaFlags, clock)
+ mediaOutputDialogFactory, mediaCarouselController, falsingManager, clock)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Set up mock views for the players
@@ -215,9 +214,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
device = device,
active = true,
resumeAction = null)
-
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
- whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
}
/**
@@ -295,9 +291,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun bindSemanticActionsOldLayout() {
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
- whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
-
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
@@ -332,9 +325,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun bindSemanticActionsNewLayout() {
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
- whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
-
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
@@ -381,9 +371,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun bindNotificationActionsNewLayout() {
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
- whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
-
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val actions = listOf(
MediaAction(icon, Runnable {}, "previous"),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 925ae30e8773..066f49a16f19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
@@ -167,7 +168,7 @@ class MediaDataManagerTest : SysuiTestCase() {
whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf(mediaRecommendationItem))
whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L)
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(false)
}
@After
@@ -594,7 +595,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testPlaybackActions_noState_usesNotification() {
val desc = "Notification Action"
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
whenever(controller.playbackState).thenReturn(null)
val notifWithAction = SbnBuilder().run {
@@ -621,7 +622,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testPlaybackActions_hasPrevNext() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY or
PlaybackState.ACTION_SKIP_TO_PREVIOUS or
PlaybackState.ACTION_SKIP_TO_NEXT
@@ -669,7 +670,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testPlaybackActions_noPrevNext_usesCustom() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4", "custom 5")
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY
val stateBuilder = PlaybackState.Builder()
.setActions(stateActions)
@@ -707,7 +708,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testPlaybackActions_reservedSpace() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY
val stateBuilder = PlaybackState.Builder()
.setActions(stateActions)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
index 962d78c129f9..b9a69bb8641a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
@@ -192,9 +192,9 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
verify(windowManager, never()).removeView(any())
}
-
+
@Test
- fun displayChip_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
+ fun setIcon_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -204,7 +204,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
+ fun setIcon_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -226,7 +226,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_hasAppIconDrawable_iconIsDrawable() {
+ fun setIcon_hasAppIconDrawable_iconIsDrawable() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -237,7 +237,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_nullAppNameAndNullPackageName_stillHasContentDescription() {
+ fun setIcon_nullAppNameAndNullPackageName_stillHasContentDescription() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -247,7 +247,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
+ fun setIcon_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -259,7 +259,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_nullAppName_iconContentDescriptionIsFromPackageName() {
+ fun setIcon_nullAppName_iconContentDescriptionIsFromPackageName() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -269,7 +269,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_hasAppName_iconContentDescriptionIsAppNameOverride() {
+ fun setIcon_hasAppName_iconContentDescriptionIsAppNameOverride() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -280,6 +280,21 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
+ fun setIcon_iconSizeMatchesGetIconSize() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(chipView, PACKAGE_NAME)
+ chipView.measure(
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ )
+
+ assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
+ assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
+ }
+
+ @Test
fun tapGestureDetected_outsideViewBounds_viewHidden() {
controllerCommon.displayChip(getState())
whenever(viewUtil.touchIsWithinView(any(), any(), any())).thenReturn(false)
@@ -344,6 +359,8 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
override fun updateChipView(chipInfo: ChipInfo, currentChipView: ViewGroup) {
}
+
+ override fun getIconSize(isAppIcon: Boolean): Int? = ICON_SIZE
}
inner class ChipInfo : ChipInfoCommon {
@@ -354,3 +371,4 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
private const val PACKAGE_NAME = "com.android.systemui"
private const val APP_NAME = "Fake App Name"
private const val TIMEOUT_MS = 10000L
+private const val ICON_SIZE = 47 \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index 355d3fe4b8d1..067607f9b8ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -174,12 +174,47 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
verify(logger).logStateChange(any(), any())
}
+ @Test
+ fun setIcon_isAppIcon_usesAppIconSize() {
+ controllerReceiver.displayChip(getChipReceiverInfo())
+ val chipView = getChipView()
+
+ controllerReceiver.setIcon(chipView, PACKAGE_NAME)
+ chipView.measure(
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ )
+
+ val expectedSize = controllerReceiver.getIconSize(isAppIcon = true)
+ assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
+ assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
+ }
+
+ @Test
+ fun setIcon_notAppIcon_usesGenericIconSize() {
+ controllerReceiver.displayChip(getChipReceiverInfo())
+ val chipView = getChipView()
+
+ controllerReceiver.setIcon(chipView, appPackageName = null)
+ chipView.measure(
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ )
+
+ val expectedSize = controllerReceiver.getIconSize(isAppIcon = false)
+ assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
+ assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
+ }
+
private fun getChipView(): ViewGroup {
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
verify(windowManager).addView(viewCaptor.capture(), any())
return viewCaptor.value as ViewGroup
}
+ private fun getChipReceiverInfo(): ChipReceiverInfo =
+ ChipReceiverInfo(routeInfo, null, null)
+
private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
index d3bb241baad4..f306fd601136 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
@@ -4,14 +4,19 @@ import static com.android.systemui.qs.tiles.dialog.InternetDialogController.MAX_
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.graphics.drawable.Drawable;
import android.testing.AndroidTestingRunner;
import android.testing.TestableResources;
@@ -30,6 +35,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -40,6 +46,7 @@ import java.util.List;
@RunWith(AndroidTestingRunner.class)
public class InternetAdapterTest extends SysuiTestCase {
+ private static final String WIFI_KEY = "Wi-Fi_Key";
private static final String WIFI_TITLE = "Wi-Fi Title";
private static final String WIFI_SUMMARY = "Wi-Fi Summary";
private static final int GEAR_ICON_RES_ID = R.drawable.ic_settings_24dp;
@@ -47,6 +54,8 @@ public class InternetAdapterTest extends SysuiTestCase {
@Rule
public MockitoRule mRule = MockitoJUnit.rule();
+ @Spy
+ private Context mSpyContext = mContext;
@Mock
private WifiEntry mInternetWifiEntry;
@@ -74,6 +83,7 @@ public class InternetAdapterTest extends SysuiTestCase {
when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
+ when(mWifiEntry.getKey()).thenReturn(WIFI_KEY);
when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
@@ -197,6 +207,66 @@ public class InternetAdapterTest extends SysuiTestCase {
}
@Test
+ public void viewHolderShouldEnabled_wifiCanConnect_returnTrue() {
+ when(mWifiEntry.canConnect()).thenReturn(true);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+ }
+
+ @Test
+ public void viewHolderShouldEnabled_wifiCanNotConnect_returnFalse() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isFalse();
+ }
+
+ @Test
+ public void viewHolderShouldEnabled_wifiCanNotConnectButCanDisconnect_returnTrue() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+ when(mWifiEntry.canConnect()).thenReturn(true);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+ }
+
+ @Test
+ public void viewHolderShouldEnabled_wifiCanNotConnectButIsSaved_returnTrue() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+ when(mWifiEntry.isSaved()).thenReturn(true);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+ }
+
+ @Test
+ public void viewHolderOnWifiClick_wifiShouldEditBeforeConnect_startActivity() {
+ when(mWifiEntry.shouldEditBeforeConnect()).thenReturn(true);
+ mViewHolder = mInternetAdapter.onCreateViewHolder(new LinearLayout(mSpyContext), 0);
+ doNothing().when(mSpyContext).startActivity(any());
+
+ mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+ verify(mSpyContext).startActivity(any());
+ }
+
+ @Test
+ public void viewHolderOnWifiClick_wifiCanConnect_connectWifi() {
+ when(mWifiEntry.canConnect()).thenReturn(true);
+
+ mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+ verify(mInternetDialogController).connect(mWifiEntry);
+ }
+
+ @Test
+ public void viewHolderOnWifiClick_wifiCanNotConnectButIsSaved_launchWifiDetailsSetting() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+ when(mWifiEntry.isSaved()).thenReturn(true);
+
+ mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+ verify(mInternetDialogController).launchWifiDetailsSetting(anyString(), any());
+ }
+
+ @Test
public void viewHolderUpdateEndIcon_wifiConnected_updateGearIcon() {
mTestableResources.addOverride(GEAR_ICON_RES_ID, mGearIcon);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index a2959e2fb917..633a9c3a03d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -385,18 +385,16 @@ public class InternetDialogControllerTest extends SysuiTestCase {
}
@Test
- public void launchWifiNetworkDetailsSetting_withNoWifiEntryKey_doNothing() {
- mInternetDialogController.launchWifiNetworkDetailsSetting(null /* key */,
- mDialogLaunchView);
+ public void launchWifiDetailsSetting_withNoWifiEntryKey_doNothing() {
+ mInternetDialogController.launchWifiDetailsSetting(null /* key */, mDialogLaunchView);
verify(mActivityStarter, never())
.postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
}
@Test
- public void launchWifiNetworkDetailsSetting_withWifiEntryKey_startActivity() {
- mInternetDialogController.launchWifiNetworkDetailsSetting("wifi_entry_key",
- mDialogLaunchView);
+ public void launchWifiDetailsSetting_withWifiEntryKey_startActivity() {
+ mInternetDialogController.launchWifiDetailsSetting("wifi_entry_key", mDialogLaunchView);
verify(mActivityStarter).postStartActivityDismissingKeyguard(any(Intent.class), anyInt(),
any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index bf16e0ab39c6..c9de60806b66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -134,6 +134,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
@Mock private InteractionJankMonitor mJankMonitor;
@Mock private StackStateLogger mStackLogger;
@Mock private NotificationStackScrollLogger mLogger;
+ @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
@@ -186,7 +187,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mShadeController,
mJankMonitor,
mStackLogger,
- mLogger
+ mLogger,
+ mNotificationStackSizeCalculator
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 56541f3ceb6f..7a92b96f40db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -103,6 +103,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
@Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@Mock private NotificationShelf mNotificationShelf;
+ @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Before
@UiThreadTest
@@ -138,7 +139,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
// holds a copy of the CUT's instances of these KeyguardBypassController, so they still
// refer to the CUT's member variables, not the spy's member variables.
mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null);
- mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper);
+ mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper,
+ mNotificationStackSizeCalculator);
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelfController(notificationShelfController);
mStackScroller.setCentralSurfaces(mCentralSurfaces);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
new file mode 100644
index 000000000000..d1848e38ca06
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2022 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.statusbar.notification.stack
+
+import android.service.notification.StatusBarNotification
+import android.testing.AndroidTestingRunner
+import android.view.View.VISIBLE
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.nullable
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NotificationStackSizeCalculatorTest : SysuiTestCase() {
+
+ @Mock private lateinit var groupManager: NotificationGroupManagerLegacy
+
+ @Mock private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
+
+ @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
+
+ @Mock private lateinit var stackLayout: NotificationStackScrollLayout
+
+ private val testableResources = mContext.getOrCreateTestableResources()
+
+ private lateinit var sizeCalculator: NotificationStackSizeCalculator
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(stackLayout.calculateGapHeight(nullable(), nullable(), any()))
+ .thenReturn(GAP_HEIGHT)
+ whenever(groupManager.isSummaryOfSuppressedGroup(any())).thenReturn(false)
+ with(testableResources) {
+ addOverride(R.integer.keyguard_max_notification_count, -1)
+ addOverride(R.dimen.notification_divider_height, NOTIFICATION_PADDING.toInt())
+ }
+
+ sizeCalculator =
+ NotificationStackSizeCalculator(
+ groupManager = groupManager,
+ lockscreenUserManager = notificationLockscreenUserManager,
+ statusBarStateController = sysuiStatusBarStateController,
+ testableResources.resources)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_zeroSpace_returnZero() {
+ val rows = listOf(createMockRow(height = ROW_HEIGHT, visibleOnLockscreen = true))
+
+ val maxNotifications =
+ computeMaxKeyguardNotifications(rows, availableSpace = 0f, shelfHeight = 0f)
+
+ assertThat(maxNotifications).isEqualTo(0)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_infiniteSpace_returnsAll() {
+ val numberOfRows = 30
+ val rows = createLockscreenRows(numberOfRows)
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, Float.MAX_VALUE)
+
+ assertThat(maxNotifications).isEqualTo(numberOfRows)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_spaceForOne_returnsOne() {
+ val rowHeight = ROW_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+ val shelfHeight =
+ totalSpaceForEachRow / 2 // In this way shelf absence will not leave room for another.
+ val spaceForOne = totalSpaceForEachRow
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications =
+ computeMaxKeyguardNotifications(
+ rows, availableSpace = spaceForOne, shelfHeight = shelfHeight)
+
+ assertThat(maxNotifications).isEqualTo(1)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_spaceForOne_shelfUsableForLastNotification_returnsTwo() {
+ val rowHeight = ROW_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+ val shelfHeight = totalSpaceForEachRow + NOTIFICATION_PADDING
+ val spaceForOne = totalSpaceForEachRow
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications =
+ computeMaxKeyguardNotifications(
+ rows, availableSpace = spaceForOne, shelfHeight = shelfHeight)
+
+ assertThat(maxNotifications).isEqualTo(1)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_invisibleOnLockscreen_returnsZero() {
+ val rows = listOf(createMockRow(visibleOnLockscreen = false))
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, Float.MAX_VALUE)
+
+ assertThat(maxNotifications).isEqualTo(0)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_spaceForTwo_returnsTwo() {
+ val rowHeight = ROW_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+ val spaceForTwo = totalSpaceForEachRow * 2 + NOTIFICATION_PADDING
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, spaceForTwo, shelfHeight = 0f)
+
+ assertThat(maxNotifications).isEqualTo(2)
+ }
+
+ @Test
+ fun computeHeight_returnsLessThanAvailableSpaceUsedToCalculateMaxNotifications() {
+ val rowHeight = ROW_HEIGHT
+ val shelfHeight = SHELF_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight + NOTIFICATION_PADDING
+ val availableSpace = totalSpaceForEachRow * 2
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
+ assertThat(maxNotifications).isEqualTo(2)
+
+ val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, SHELF_HEIGHT)
+ assertThat(height).isAtMost(availableSpace + SHELF_HEIGHT)
+ }
+
+ @Test
+ fun computeHeight_allInvisibleToLockscreen_NotInLockscreen_returnsHigherThanZero() {
+ setOnLockscreen(false)
+ val rowHeight = 10f
+ setupChildren(listOf(createMockRow(rowHeight, visibleOnLockscreen = false)))
+
+ val height =
+ sizeCalculator.computeHeight(
+ stackLayout, maxNotifications = Int.MAX_VALUE, SHELF_HEIGHT)
+
+ assertThat(height).isGreaterThan(rowHeight)
+ }
+
+ @Test
+ fun computeHeight_allInvisibleToLockscreen_onLockscreen_returnsZero() {
+ setOnLockscreen(true)
+ setupChildren(listOf(createMockRow(visibleOnLockscreen = false)))
+
+ val height =
+ sizeCalculator.computeHeight(
+ stackLayout, maxNotifications = Int.MAX_VALUE, SHELF_HEIGHT)
+
+ assertThat(height).isEqualTo(0)
+ }
+
+ private fun computeMaxKeyguardNotifications(
+ rows: List<ExpandableView>,
+ availableSpace: Float,
+ shelfHeight: Float = SHELF_HEIGHT
+ ): Int {
+ setupChildren(rows)
+ return sizeCalculator.computeMaxKeyguardNotifications(
+ stackLayout, availableSpace, shelfHeight)
+ }
+
+ private fun setupChildren(children: List<ExpandableView>) {
+ whenever(stackLayout.getChildAt(any())).thenAnswer { invocation ->
+ val inx = invocation.getArgument<Int>(0)
+ return@thenAnswer children[inx]
+ }
+ whenever(stackLayout.childCount).thenReturn(children.size)
+ }
+
+ private fun createLockscreenRows(number: Int): List<ExpandableNotificationRow> =
+ (1..number).map { createMockRow(visibleOnLockscreen = true) }.toList()
+
+ private fun createMockRow(
+ height: Float = ROW_HEIGHT,
+ visibleOnLockscreen: Boolean = true,
+ isRemoved: Boolean = false,
+ visibility: Int = VISIBLE,
+ summaryOfSuppressed: Boolean = false
+ ): ExpandableNotificationRow {
+ val row = mock(ExpandableNotificationRow::class.java)
+ val entry = mock(NotificationEntry::class.java)
+ val sbn = mock(StatusBarNotification::class.java)
+ whenever(entry.sbn).thenReturn(sbn)
+ whenever(row.entry).thenReturn(entry)
+ whenever(row.isRemoved).thenReturn(isRemoved)
+ whenever(row.visibility).thenReturn(visibility)
+ whenever(notificationLockscreenUserManager.shouldShowOnKeyguard(entry))
+ .thenReturn(visibleOnLockscreen)
+ whenever(groupManager.isSummaryOfSuppressedGroup(sbn)).thenReturn(summaryOfSuppressed)
+ whenever(row.getMinHeight(any())).thenReturn(height.toInt())
+ whenever(row.intrinsicHeight).thenReturn(height.toInt())
+ return row
+ }
+
+ private fun setOnLockscreen(onLockscreen: Boolean) {
+ whenever(sysuiStatusBarStateController.state)
+ .thenReturn(
+ if (onLockscreen) {
+ KEYGUARD
+ } else {
+ SHADE
+ })
+ }
+
+ /** Default dimensions for tests that don't overwrite them. */
+ companion object {
+ const val GAP_HEIGHT = 12f
+ const val NOTIFICATION_PADDING = 3f
+ const val SHELF_HEIGHT = 14f
+ const val ROW_HEIGHT = SHELF_HEIGHT * 3
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 4bac08ea536b..06b20380c0ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -104,7 +104,6 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -119,12 +118,12 @@ import com.android.systemui.statusbar.notification.ConversationNotificationManag
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
@@ -174,8 +173,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock
private NotificationShelfController mNotificationShelfController;
@Mock
- private NotificationGroupManagerLegacy mGroupManager;
- @Mock
private KeyguardStatusBarView mKeyguardStatusBar;
@Mock
private KeyguardUserSwitcherView mUserSwitcherView;
@@ -200,10 +197,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock
private DynamicPrivacyController mDynamicPrivacyController;
@Mock
- private ShadeController mShadeController;
- @Mock
- private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
- @Mock
private NotificationEntryManager mNotificationEntryManager;
@Mock
private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@@ -336,6 +329,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
private SysUiState mSysUiState;
@Mock
private NotificationListContainer mNotificationListContainer;
+ @Mock
+ private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter;
private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
private SysuiStatusBarStateController mStatusBarStateController;
@@ -466,7 +461,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mFeatureFlags,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, new FalsingCollectorFake(),
- mNotificationLockscreenUserManager, mNotificationEntryManager,
+ mNotificationEntryManager,
mKeyguardStateController,
mStatusBarStateController,
mStatusBarWindowStateController,
@@ -484,7 +479,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mKeyguardUserSwitcherComponentFactory,
mKeyguardStatusBarViewComponentFactory,
mLockscreenShadeTransitionController,
- mGroupManager,
mNotificationAreaController,
mAuthController,
mScrimController,
@@ -516,7 +510,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mSysUiState,
mKeyguardUnlockAnimationController,
mNotificationListContainer,
- mPanelEventsEmitter);
+ mPanelEventsEmitter,
+ mNotificationStackSizeCalculator);
mNotificationPanelViewController.initDependencies(
mCentralSurfaces,
() -> {},
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 249ee16afaae..61e3da8aae51 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -322,28 +322,28 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
@Override
public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
boolean enabled) {
- mService.setImeSessionEnabled(sessions, enabled);
+ mService.scheduleSetImeSessionEnabled(sessions, enabled);
}
@Override
public void unbindInput() {
- mService.unbindInput();
+ mService.scheduleUnbindInput();
}
@Override
public void bindInput(InputBinding binding) {
- mService.bindInput(binding);
+ mService.scheduleBindInput(binding);
}
@Override
public void createImeSession(ArraySet<Integer> ignoreSet) {
- mService.createImeSession(ignoreSet);
+ mService.scheduleCreateImeSession(ignoreSet);
}
@Override
public void startInput(IBinder startInputToken, IInputContext inputContext,
EditorInfo editorInfo, boolean restarting) {
- mService.startInput(startInputToken, inputContext, editorInfo, restarting);
+ mService.scheduleStartInput(startInputToken, inputContext, editorInfo, restarting);
}
}
@@ -4377,12 +4377,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*
* @param binding Information given to an accessibility service about a client connecting to it.
*/
- public void bindInput(InputBinding binding) {
- AccessibilityUserState userState;
+ public void scheduleBindInput(InputBinding binding) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::bindInput, this,
+ binding));
+ }
+
+ private void bindInput(InputBinding binding) {
synchronized (mLock) {
// Keep records of these in case new Accessibility Services are enabled.
mInputBinding = binding;
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (service.requestImeApis()) {
@@ -4395,11 +4399,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
/**
* Unbind input for accessibility services which request ime capabilities.
*/
- public void unbindInput() {
- AccessibilityUserState userState;
- // TODO(b/218182733): Resolve the Imf lock and mLock possible deadlock
+ public void scheduleUnbindInput() {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::unbindInput, this));
+ }
+
+ private void unbindInput() {
synchronized (mLock) {
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (service.requestImeApis()) {
@@ -4412,16 +4418,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
/**
* Start input for accessibility services which request ime capabilities.
*/
- public void startInput(IBinder startInputToken, IInputContext inputContext,
+ public void scheduleStartInput(IBinder startInputToken, IInputContext inputContext,
+ EditorInfo editorInfo, boolean restarting) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::startInput, this,
+ startInputToken, inputContext, editorInfo, restarting));
+ }
+
+ private void startInput(IBinder startInputToken, IInputContext inputContext,
EditorInfo editorInfo, boolean restarting) {
- AccessibilityUserState userState;
synchronized (mLock) {
// Keep records of these in case new Accessibility Services are enabled.
mStartInputToken = startInputToken;
mInputContext = inputContext;
mEditorInfo = editorInfo;
mRestarting = restarting;
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (service.requestImeApis()) {
@@ -4435,11 +4446,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
* Request input sessions from all accessibility services which request ime capabilities and
* whose id is not in the ignoreSet
*/
- public void createImeSession(ArraySet<Integer> ignoreSet) {
- AccessibilityUserState userState;
+ public void scheduleCreateImeSession(ArraySet<Integer> ignoreSet) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::createImeSession,
+ this, ignoreSet));
+ }
+
+ private void createImeSession(ArraySet<Integer> ignoreSet) {
synchronized (mLock) {
mInputSessionRequested = true;
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if ((!ignoreSet.contains(service.mId)) && service.requestImeApis()) {
@@ -4455,10 +4470,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
* @param sessions Sessions to enable or disable.
* @param enabled True if enable the sessions or false if disable the sessions.
*/
- public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions, boolean enabled) {
- AccessibilityUserState userState;
+ public void scheduleSetImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
+ boolean enabled) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::setImeSessionEnabled,
+ this, sessions, enabled));
+ }
+
+ private void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions, boolean enabled) {
synchronized (mLock) {
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (sessions.contains(service.mId) && service.requestImeApis()) {
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index bf8b18ce3157..7a5fa628f645 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -51,6 +51,7 @@ import android.os.Parcel;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
+import android.util.Log;
import android.util.PackageUtils;
import android.util.Slog;
@@ -332,13 +333,28 @@ class AssociationRequestsProcessor {
}
}
- String[] sameOemPackages = mContext.getResources()
+ // Below we check if the requesting package is allowlisted (usually by the OEM) for creating
+ // CDM associations without user confirmation (prompt).
+ // For this we'll check to config arrays:
+ // - com.android.internal.R.array.config_companionDevicePackages
+ // and
+ // - com.android.internal.R.array.config_companionDeviceCerts.
+ // Both arrays are expected to contain similar number of entries.
+ // config_companionDevicePackages contains package names of the allowlisted packages.
+ // config_companionDeviceCerts contains SHA256 digests of the signatures of the
+ // corresponding packages.
+ // If a package may be signed with one of several certificates, its package name would
+ // appear multiple times in the config_companionDevicePackages, with different entries
+ // (one for each of the valid signing certificates) at the corresponding positions in
+ // config_companionDeviceCerts.
+ final String[] allowlistedPackages = mContext.getResources()
.getStringArray(com.android.internal.R.array.config_companionDevicePackages);
- if (!ArrayUtils.contains(sameOemPackages, packageName)) {
- Slog.w(TAG, packageName
- + " can not silently create associations due to no package found."
- + " Packages from OEM: " + Arrays.toString(sameOemPackages)
- );
+ if (!ArrayUtils.contains(allowlistedPackages, packageName)) {
+ if (DEBUG) {
+ Log.d(TAG, packageName + " is not allowlisted for creating associations "
+ + "without user confirmation (prompt)");
+ Log.v(TAG, "Allowlisted packages=" + Arrays.toString(allowlistedPackages));
+ }
return false;
}
@@ -361,44 +377,41 @@ class AssociationRequestsProcessor {
}
}
- String[] sameOemCerts = mContext.getResources()
+ final String[] allowlistedPackagesSignatureDigests = mContext.getResources()
.getStringArray(com.android.internal.R.array.config_companionDeviceCerts);
-
- Signature[] signatures = mPackageManager.getPackage(packageName).getSigningDetails()
- .getSignatures();
- String[] apkCerts = PackageUtils.computeSignaturesSha256Digests(signatures);
-
- Set<String> sameOemPackageCerts =
- getSameOemPackageCerts(packageName, sameOemPackages, sameOemCerts);
-
- for (String cert : apkCerts) {
- if (sameOemPackageCerts.contains(cert)) {
- return true;
+ final Set<String> allowlistedSignatureDigestsForRequestingPackage = new HashSet<>();
+ for (int i = 0; i < allowlistedPackages.length; i++) {
+ if (allowlistedPackages[i].equals(packageName)) {
+ final String digest = allowlistedPackagesSignatureDigests[i].replaceAll(":", "");
+ allowlistedSignatureDigestsForRequestingPackage.add(digest);
}
}
- Slog.w(TAG, packageName
- + " can not silently create associations. " + packageName
- + " has SHA256 certs from APK: " + Arrays.toString(apkCerts)
- + " and from OEM: " + Arrays.toString(sameOemCerts)
- );
+ final Signature[] requestingPackageSignatures = mPackageManager.getPackage(packageName)
+ .getSigningDetails().getSignatures();
+ final String[] requestingPackageSignatureDigests =
+ PackageUtils.computeSignaturesSha256Digests(requestingPackageSignatures);
- return false;
- }
-
- private static Set<String> getSameOemPackageCerts(
- String packageName, String[] oemPackages, String[] sameOemCerts) {
- Set<String> sameOemPackageCerts = new HashSet<>();
+ boolean requestingPackageSignatureAllowlisted = false;
+ for (String signatureDigest : requestingPackageSignatureDigests) {
+ if (allowlistedSignatureDigestsForRequestingPackage.contains(signatureDigest)) {
+ requestingPackageSignatureAllowlisted = true;
+ break;
+ }
+ }
- // Assume OEM may enter same package name in the parallel string array with
- // multiple APK certs corresponding to it
- for (int i = 0; i < oemPackages.length; i++) {
- if (oemPackages[i].equals(packageName)) {
- sameOemPackageCerts.add(sameOemCerts[i].replaceAll(":", ""));
+ if (!requestingPackageSignatureAllowlisted) {
+ Slog.w(TAG, "Certificate mismatch for allowlisted package " + packageName);
+ if (DEBUG) {
+ Log.d(TAG, " > allowlisted signatures for " + packageName + ": ["
+ + String.join(", ", allowlistedSignatureDigestsForRequestingPackage)
+ + "]");
+ Log.d(TAG, " > actual signatures for " + packageName + ": "
+ + Arrays.toString(requestingPackageSignatureDigests));
}
}
- return sameOemPackageCerts;
+ return requestingPackageSignatureAllowlisted;
}
/**
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index 4c7b9b80d5be..a6bd48056e12 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -51,12 +51,12 @@ class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDe
void onBindingDied(@UserIdInt int userId, @NonNull String packageName);
}
- @UserIdInt
- private final int mUserId;
- @NonNull
- private final ComponentName mComponentName;
- @Nullable
- private Listener mListener;
+ private final @UserIdInt int mUserId;
+ private final @NonNull ComponentName mComponentName;
+ // IMPORTANT: this can (and will!) be null (at the moment, CompanionApplicationController only
+ // installs a listener to the primary ServiceConnector), hence we should always null-check the
+ // reference before calling on it.
+ private @Nullable Listener mListener;
/**
* Create a CompanionDeviceServiceConnector instance.
@@ -125,7 +125,9 @@ class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDe
if (DEBUG) Log.d(TAG, "onBindingDied() " + mComponentName.toShortString());
- mListener.onBindingDied(mUserId, mComponentName.getPackageName());
+ if (mListener != null) {
+ mListener.onBindingDied(mUserId, mComponentName.getPackageName());
+ }
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9d9ee8c7a03b..db2c566e8337 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9209,6 +9209,10 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppRestrictionController.dump(pw, "");
}
+ void dumpAppRestrictionController(ProtoOutputStream proto, int uid) {
+ mAppRestrictionController.dumpAsProto(proto, uid);
+ }
+
/**
* Wrapper function to print out debug data filtered by specified arguments.
*/
@@ -9321,6 +9325,29 @@ public class ActivityManagerService extends IActivityManager.Stub
mProcessList.writeProcessesToProtoLSP(proto, dumpPackage);
}
}
+ } else if ("app-restrictions".equals(cmd)) {
+ int uid = Process.INVALID_UID;
+ boolean error = false;
+ for (int i = 0; i < args.length; i++) {
+ if ("--uid".equals(args[i])) {
+ if (i + 1 < args.length) {
+ try {
+ uid = Integer.parseInt(args[i + 1]);
+ } catch (NumberFormatException e) {
+ error = true;
+ }
+ } else {
+ error = true;
+ }
+ break;
+ }
+ }
+ if (error) {
+ pw.println("Invalid --uid argument");
+ pw.println("Use -h for help.");
+ } else {
+ dumpAppRestrictionController(proto, uid);
+ }
} else {
// default option, dump everything, output is ActivityManagerServiceProto
synchronized (this) {
diff --git a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
index d1cf0049d146..6f11b0001c7a 100644
--- a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
@@ -26,10 +26,13 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.SystemClock;
+import android.util.ArrayMap;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
import com.android.server.am.AppBatteryExemptionTracker.UidBatteryStates;
@@ -65,6 +68,11 @@ final class AppBatteryExemptionTracker
// As it's a UID-based tracker, anywhere which requires a package name, use this default name.
static final String DEFAULT_NAME = "";
+ // As it's a UID-based tracker, while the state change event it receives could be
+ // in the combination of UID + package name, we'd have to leverage each package's state.
+ @GuardedBy("mLock")
+ private UidProcessMap<Integer> mUidPackageStates = new UidProcessMap<>();
+
AppBatteryExemptionTracker(Context context, AppRestrictionController controller) {
this(context, controller, null, null);
}
@@ -103,12 +111,75 @@ final class AppBatteryExemptionTracker
.getUidBatteryUsage(uid);
final int stateTypeIndex = stateTypeToIndex(stateType);
synchronized (mLock) {
- UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
- if (pkg == null) {
- pkg = createAppStateEvents(uid, DEFAULT_NAME);
- mPkgEvents.put(uid, DEFAULT_NAME, pkg);
+ final SparseArray<ArrayMap<String, Integer>> map = mUidPackageStates.getMap();
+ ArrayMap<String, Integer> pkgsStates = map.get(uid);
+ if (pkgsStates == null) {
+ pkgsStates = new ArrayMap<>();
+ map.put(uid, pkgsStates);
+ }
+ int states = 0;
+ int indexOfPkg = pkgsStates.indexOfKey(packageName);
+ if (indexOfPkg >= 0) {
+ states = pkgsStates.valueAt(indexOfPkg);
+ } else {
+ pkgsStates.put(packageName, 0);
+ indexOfPkg = pkgsStates.indexOfKey(packageName);
+ }
+ boolean addEvent = false;
+ if (start) {
+ // Check if there is another package within this UID with this type of event start.
+ boolean alreadyStarted = false;
+ for (int i = pkgsStates.size() - 1; i >= 0; i--) {
+ final int s = pkgsStates.valueAt(i);
+ if ((s & stateType) != 0) {
+ alreadyStarted = true;
+ break;
+ }
+ }
+ pkgsStates.setValueAt(indexOfPkg, states | stateType);
+ if (!alreadyStarted) {
+ // This is the first package within this UID with this type of event start.
+ addEvent = true;
+ }
+ } else {
+ states &= ~stateType;
+ pkgsStates.setValueAt(indexOfPkg, states);
+ boolean allStopped = true;
+ for (int i = pkgsStates.size() - 1; i >= 0; i--) {
+ final int s = pkgsStates.valueAt(i);
+ if ((s & stateType) != 0) {
+ allStopped = false;
+ break;
+ }
+ }
+ if (allStopped) {
+ // None of the packages in this UID has an active event of this type.
+ addEvent = true;
+ }
+ if (states == 0) { // None of the states of this package are active, prune it.
+ pkgsStates.removeAt(indexOfPkg);
+ if (pkgsStates.size() == 0) {
+ map.remove(uid);
+ }
+ }
+ }
+ if (addEvent) {
+ UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
+ if (pkg == null) {
+ pkg = createAppStateEvents(uid, DEFAULT_NAME);
+ mPkgEvents.put(uid, DEFAULT_NAME, pkg);
+ }
+ pkg.addEvent(start, now, batteryUsage, stateTypeIndex);
}
- pkg.addEvent(start, now, batteryUsage, stateTypeIndex);
+ }
+ }
+
+ @VisibleForTesting
+ @Override
+ void reset() {
+ super.reset();
+ synchronized (mLock) {
+ mUidPackageStates.clear();
}
}
@@ -116,6 +187,7 @@ final class AppBatteryExemptionTracker
if (!enabled) {
synchronized (mLock) {
mPkgEvents.clear();
+ mUidPackageStates.clear();
}
}
}
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index ea1e3357c4dc..b7185ed7a302 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -46,6 +46,7 @@ import android.content.Context;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.os.AppBatteryStatsProto;
import android.os.BatteryConsumer;
import android.os.BatteryConsumer.Dimensions;
import android.os.BatteryStatsInternal;
@@ -62,6 +63,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -676,6 +678,63 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
super.dump(pw, prefix);
}
+ @Override
+ void dumpAsProto(ProtoOutputStream proto, int uid) {
+ synchronized (mLock) {
+ final SparseArray<ImmutableBatteryUsage> uidConsumers = mUidBatteryUsageInWindow;
+ if (uid != android.os.Process.INVALID_UID) {
+ final BatteryUsage usage = uidConsumers.get(uid);
+ if (usage != null) {
+ dumpUidStats(proto, uid, usage);
+ }
+ } else {
+ for (int i = 0, size = uidConsumers.size(); i < size; i++) {
+ final int aUid = uidConsumers.keyAt(i);
+ final BatteryUsage usage = uidConsumers.valueAt(i);
+ dumpUidStats(proto, aUid, usage);
+ }
+ }
+ }
+ }
+
+ private void dumpUidStats(ProtoOutputStream proto, int uid, BatteryUsage usage) {
+ if (usage.mUsage == null) {
+ return;
+ }
+
+ final double foregroundUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND);
+ final double backgroundUsage = usage.getUsagePowerMah(PROCESS_STATE_BACKGROUND);
+ final double fgsUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND_SERVICE);
+
+ if (foregroundUsage == 0 && backgroundUsage == 0 && fgsUsage == 0) {
+ return;
+ }
+
+ final long token = proto.start(AppBatteryStatsProto.UID_STATS);
+ proto.write(AppBatteryStatsProto.UidStats.UID, uid);
+ dumpProcessStateStats(proto,
+ AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND,
+ foregroundUsage);
+ dumpProcessStateStats(proto,
+ AppBatteryStatsProto.UidStats.ProcessStateStats.BACKGROUND,
+ backgroundUsage);
+ dumpProcessStateStats(proto,
+ AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND_SERVICE,
+ fgsUsage);
+ proto.end(token);
+ }
+
+ private void dumpProcessStateStats(ProtoOutputStream proto, int processState, double powerMah) {
+ if (powerMah == 0) {
+ return;
+ }
+
+ final long token = proto.start(AppBatteryStatsProto.UidStats.PROCESS_STATE_STATS);
+ proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.PROCESS_STATE, processState);
+ proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.POWER_MAH, powerMah);
+ proto.end(token);
+ }
+
static class BatteryUsage {
static final int BATTERY_USAGE_INDEX_UNSPECIFIED = PROCESS_STATE_UNSPECIFIED;
static final int BATTERY_USAGE_INDEX_FOREGROUND = PROCESS_STATE_FOREGROUND;
@@ -795,6 +854,15 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
return formatBatteryUsage(mUsage);
}
+ double getUsagePowerMah(@BatteryConsumer.ProcessState int processState) {
+ switch (processState) {
+ case PROCESS_STATE_FOREGROUND: return mUsage[1];
+ case PROCESS_STATE_BACKGROUND: return mUsage[2];
+ case PROCESS_STATE_FOREGROUND_SERVICE: return mUsage[3];
+ }
+ return 0;
+ }
+
boolean isValid() {
for (int i = 0; i < mUsage.length; i++) {
if (mUsage[i] < 0.0d) {
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index dc8403aea1b3..15484b2d618e 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -135,6 +135,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArrayMap;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -1369,6 +1370,12 @@ public final class AppRestrictionController {
}
}
+ void dumpAsProto(ProtoOutputStream proto, int uid) {
+ for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
+ mAppStateTrackers.get(i).dumpAsProto(proto, uid);
+ }
+ }
+
private void applyRestrictionLevel(String pkgName, int uid, @RestrictionLevel int level,
int curBucket, boolean allowUpdateBucket, int reason, int subReason) {
int curLevel;
diff --git a/services/core/java/com/android/server/am/BaseAppStateTracker.java b/services/core/java/com/android/server/am/BaseAppStateTracker.java
index 0fada53d622e..daff4c1c6424 100644
--- a/services/core/java/com/android/server/am/BaseAppStateTracker.java
+++ b/services/core/java/com/android/server/am/BaseAppStateTracker.java
@@ -35,6 +35,7 @@ import android.os.BatteryStatsInternal;
import android.os.Handler;
import android.permission.PermissionManager;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
@@ -250,6 +251,9 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
mInjector.getPolicy().dump(pw, " " + prefix);
}
+ void dumpAsProto(ProtoOutputStream proto, int uid) {
+ }
+
static class Injector<T extends BaseAppStatePolicy> {
T mAppStatePolicy;
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index e9205230a4ad..67d6d3111955 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -85,15 +85,6 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
Slog.w(TAG, "Failed to send connected event", ex);
}
}
-
- @Override
- public void onDisconnected(@NonNull IGameService service) {
- try {
- service.disconnected();
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to send disconnected event", ex);
- }
- }
};
private final ServiceLifecycleCallbacks<IGameSessionService>
@@ -181,7 +172,8 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
}
@Override
- public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {}
+ public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+ }
};
private final IGameServiceController mGameServiceController =
@@ -338,7 +330,9 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
destroyAndClearAllGameSessionsLocked();
- mGameServiceConnector.unbind();
+ mGameServiceConnector.post(IGameService::disconnected).whenComplete((result, t) -> {
+ mGameServiceConnector.unbind();
+ });
mGameSessionServiceConnector.unbind();
mGameServiceConnector.setServiceLifecycleCallbacks(null);
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 1b2e606117e7..1370fd83f6a8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -38,7 +38,7 @@ import java.util.NoSuchElementException;
*/
public abstract class BaseClientMonitor implements IBinder.DeathRecipient {
- private static final String TAG = "Biometrics/ClientMonitor";
+ private static final String TAG = "BaseClientMonitor";
protected static final boolean DEBUG = true;
// Counter used to distinguish between ClientMonitor instances to help debugging.
@@ -120,8 +120,18 @@ public abstract class BaseClientMonitor implements IBinder.DeathRecipient {
}
/**
+ * Sets the lifecycle callback before the operation is started via
+ * {@link #start(ClientMonitorCallback)} when the client must wait for a cookie before starting.
+ *
+ * @param callback lifecycle callback (typically same callback used for starting the operation)
+ */
+ public void waitForCookie(@NonNull ClientMonitorCallback callback) {
+ mCallback = callback;
+ }
+
+ /**
* Starts the ClientMonitor's lifecycle.
- * @param callback invoked when the operation is complete (succeeds, fails, etc)
+ * @param callback invoked when the operation is complete (succeeds, fails, etc.)
*/
public void start(@NonNull ClientMonitorCallback callback) {
mCallback = wrapCallbackForStart(callback);
@@ -246,12 +256,12 @@ public abstract class BaseClientMonitor implements IBinder.DeathRecipient {
}
/** Unique request id. */
- public final long getRequestId() {
+ public long getRequestId() {
return mRequestId;
}
/** If a unique id has been set via {@link #setRequestId(long)} */
- public final boolean hasRequestId() {
+ public boolean hasRequestId() {
return mRequestId > 0;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index d0ec4470d3e6..19a93f30937f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -285,7 +285,7 @@ public class BiometricScheduler {
// Not all operations start immediately. BiometricPrompt waits for its operation
// to arrive at the head of the queue, before pinging it to start.
- final int cookie = mCurrentOperation.isReadyToStart();
+ final int cookie = mCurrentOperation.isReadyToStart(mInternalCallback);
if (cookie == 0) {
if (!mCurrentOperation.start(mInternalCallback)) {
// Note down current length of queue
@@ -463,6 +463,18 @@ public class BiometricScheduler {
return mCurrentOperation != null ? mCurrentOperation.getClientMonitor() : null;
}
+ /** The current operation if the requestId is set and matches. */
+ @Deprecated
+ @Nullable
+ public BaseClientMonitor getCurrentClientIfMatches(long requestId) {
+ if (mCurrentOperation != null) {
+ if (mCurrentOperation.isMatchingRequestId(requestId)) {
+ return mCurrentOperation.getClientMonitor();
+ }
+ }
+ return null;
+ }
+
public int getCurrentPendingCount() {
return mPendingOperations.size();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
index 15f0cadced99..968146a166ed 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
@@ -123,11 +123,12 @@ public class BiometricSchedulerOperation {
*
* @return cookie or 0 if ready/started
*/
- public int isReadyToStart() {
+ public int isReadyToStart(@NonNull ClientMonitorCallback callback) {
if (mState == STATE_WAITING_FOR_COOKIE || mState == STATE_WAITING_IN_QUEUE) {
final int cookie = mClientMonitor.getCookie();
if (cookie != 0) {
mState = STATE_WAITING_FOR_COOKIE;
+ mClientMonitor.waitForCookie(getWrappedCallback(callback));
}
return cookie;
}
@@ -137,7 +138,7 @@ public class BiometricSchedulerOperation {
/**
* Start this operation without waiting for a cookie
- * (i.e. {@link #isReadyToStart() returns zero}
+ * (i.e. {@link #isReadyToStart(ClientMonitorCallback)} returns zero}
*
* @param callback lifecycle callback
* @return if this operation started
diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
index 008717899aba..aeb6b6e2a907 100644
--- a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
+++ b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
@@ -84,7 +84,8 @@ public final class SensorOverlays {
};
try {
- mUdfpsOverlayController.get().showUdfpsOverlay(sensorId, reason, callback);
+ mUdfpsOverlayController.get().showUdfpsOverlay(
+ client.getRequestId(), sensorId, reason, callback);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
index 4f900208841e..a0999771a1be 100644
--- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
@@ -57,30 +57,25 @@ public class UserAwareBiometricScheduler extends BiometricScheduler {
@Nullable private StopUserClient<?> mStopUserClient;
private class ClientFinishedCallback implements ClientMonitorCallback {
- private final BaseClientMonitor mOwner;
+ @NonNull private final BaseClientMonitor mOwner;
- ClientFinishedCallback(BaseClientMonitor owner) {
+ ClientFinishedCallback(@NonNull BaseClientMonitor owner) {
mOwner = owner;
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
mHandler.post(() -> {
- if (mOwner != clientMonitor) {
- Slog.e(getTag(), "[Wrong client finished], actual: "
- + clientMonitor + ", expected: " + mOwner);
- return;
- }
-
Slog.d(getTag(), "[Client finished] " + clientMonitor + ", success: " + success);
if (mCurrentOperation != null && mCurrentOperation.isFor(mOwner)) {
mCurrentOperation = null;
- startNextOperationIfIdle();
} else {
- // can usually be ignored (hal died, etc.)
- Slog.d(getTag(), "operation is already null or different (reset?): "
+ // can happen if the hal dies and is usually okay
+ // do not unset the current operation that may be newer
+ Slog.w(getTag(), "operation is already null or different (reset?): "
+ mCurrentOperation);
}
+ startNextOperationIfIdle();
});
}
}
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 b4befd23671f..e8d8fb828542 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
@@ -928,7 +928,8 @@ public class FingerprintService extends SystemService {
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -936,11 +937,11 @@ public class FingerprintService extends SystemService {
Slog.w(TAG, "No matching provider for onFingerDown, sensorId: " + sensorId);
return;
}
- provider.onPointerDown(sensorId, x, y, minor, major);
+ provider.onPointerDown(requestId, sensorId, x, y, minor, major);
}
@Override
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -948,11 +949,11 @@ public class FingerprintService extends SystemService {
Slog.w(TAG, "No matching provider for onFingerUp, sensorId: " + sensorId);
return;
}
- provider.onPointerUp(sensorId);
+ provider.onPointerUp(requestId, sensorId);
}
@Override
- public void onUiReady(int sensorId) {
+ public void onUiReady(long requestId, int sensorId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -960,7 +961,7 @@ public class FingerprintService extends SystemService {
Slog.w(TAG, "No matching provider for onUiReady, sensorId: " + sensorId);
return;
}
- provider.onUiReady(sensorId);
+ provider.onUiReady(requestId, sensorId);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 0bdc4ebad66e..9cdbdc9158fb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -142,11 +142,11 @@ public interface ServiceProvider {
long getAuthenticatorId(int sensorId, int userId);
- void onPointerDown(int sensorId, int x, int y, float minor, float major);
+ void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major);
- void onPointerUp(int sensorId);
+ void onPointerUp(long requestId, int sensorId);
- void onUiReady(int sensorId);
+ void onUiReady(long requestId, int sensorId);
void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index f810bca9707d..1fac8a8ce5c9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -580,39 +580,37 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClient();
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.e(getTag(), "onPointerDown received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerDown(x, y, minor, major);
+ ((Udfps) client).onPointerDown(x, y, minor, major);
}
@Override
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClient();
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.e(getTag(), "onPointerUp received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerUp();
+ ((Udfps) client).onPointerUp();
}
@Override
- public void onUiReady(int sensorId) {
+ public void onUiReady(long requestId, int sensorId) {
final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClient();
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.e(getTag(), "onUiReady received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onUiReady();
+ ((Udfps) client).onUiReady();
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 9d60859a4a21..1d2a3655021c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -792,36 +792,34 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
+ final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.w(TAG, "onFingerDown received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerDown(x, y, minor, major);
+ ((Udfps) client).onPointerDown(x, y, minor, major);
}
@Override
- public void onPointerUp(int sensorId) {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
+ public void onPointerUp(long requestId, int sensorId) {
+ final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.w(TAG, "onFingerDown received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerUp();
+ ((Udfps) client).onPointerUp();
}
@Override
- public void onUiReady(int sensorId) {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
+ public void onUiReady(long requestId, int sensorId) {
+ final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.w(TAG, "onUiReady received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onUiReady();
+ ((Udfps) client).onUiReady();
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 149526f21fdb..a4e343e786c1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -441,7 +441,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y, float minor,
+ float major) {
mHandler.post(() -> {
Slog.d(TAG, "onFingerDown");
final AuthenticationConsumer lastAuthenticatedConsumer =
@@ -488,7 +489,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
}
@Override
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
mHandler.post(() -> {
Slog.d(TAG, "onFingerUp");
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 8921fee6c8e0..c8f809b6782f 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1827,9 +1827,9 @@ class ShortcutPackage extends ShortcutPackageItem {
ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
final Map<String, Map<String, List<String>>> capabilityBindings =
- si.getCapabilityBindings();
+ si.getCapabilityBindingsInternal();
if (capabilityBindings != null && !capabilityBindings.isEmpty()) {
- XmlUtils.writeMapXml(si.getCapabilityBindings(), NAME_CAPABILITY, out);
+ XmlUtils.writeMapXml(capabilityBindings, NAME_CAPABILITY, out);
}
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index b3239486a75f..f255db4a9801 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -242,6 +242,11 @@ public class ParsingPackageUtils {
public static final int PARSE_CHATTY = 1 << 31;
+ /** The total maximum number of activities, services, providers and activity-aliases */
+ private static final int MAX_NUM_COMPONENTS = 30000;
+ private static final String MAX_NUM_COMPONENTS_ERR_MSG =
+ "Total number of components has exceeded the maximum number: " + MAX_NUM_COMPONENTS;
+
@IntDef(flag = true, prefix = { "PARSE_" }, value = {
PARSE_CHATTY,
PARSE_COLLECT_CERTIFICATES,
@@ -837,11 +842,20 @@ public class ParsingPackageUtils {
if (result.isError()) {
return input.error(result);
}
+
+ if (hasTooManyComponents(pkg)) {
+ return input.error(MAX_NUM_COMPONENTS_ERR_MSG);
+ }
}
return input.success(pkg);
}
+ private static boolean hasTooManyComponents(ParsingPackage pkg) {
+ return pkg.getActivities().size() + pkg.getServices().size() + pkg.getProviders().size()
+ > MAX_NUM_COMPONENTS;
+ }
+
/**
* For parsing non-MainComponents. Main ones have an order and some special handling which is
* done directly in {@link #parseSplitApplication(ParseInput, ParsingPackage, Resources,
@@ -2145,6 +2159,9 @@ public class ParsingPackageUtils {
if (result.isError()) {
return input.error(result);
}
+ if (hasTooManyComponents(pkg)) {
+ return input.error(MAX_NUM_COMPONENTS_ERR_MSG);
+ }
}
if (TextUtils.isEmpty(pkg.getStaticSharedLibName()) && TextUtils.isEmpty(
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index c252043028c9..672458bef4a7 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -665,42 +665,6 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
- public void prepare(String tiasId, int type, int userId) {
- // TODO: bind service
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, "prepare");
- final long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- UserState userState = getOrCreateUserStateLocked(resolvedUserId);
- TvInteractiveAppState iAppState = userState.mIAppMap.get(tiasId);
- if (iAppState == null) {
- Slogf.e(TAG, "failed to prepare TIAS - unknown TIAS id " + tiasId);
- return;
- }
- ComponentName componentName = iAppState.mInfo.getComponent();
- ServiceState serviceState = userState.mServiceStateMap.get(componentName);
- if (serviceState == null) {
- serviceState = new ServiceState(
- componentName, tiasId, resolvedUserId, true, type);
- userState.mServiceStateMap.put(componentName, serviceState);
- updateServiceConnectionLocked(componentName, resolvedUserId);
- } else if (serviceState.mService != null) {
- serviceState.mService.prepare(type);
- } else {
- serviceState.mPendingPrepare = true;
- serviceState.mPendingPrepareType = type;
- updateServiceConnectionLocked(componentName, resolvedUserId);
- }
- }
- } catch (RemoteException e) {
- Slogf.e(TAG, "error in prepare", e);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Override
public void registerAppLinkInfo(String tiasId, AppLinkInfo appLinkInfo, int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "registerAppLinkInfo: " + appLinkInfo);
@@ -1705,7 +1669,6 @@ public class TvInteractiveAppManagerService extends SystemService {
}
boolean shouldBind = (!serviceState.mSessionTokens.isEmpty())
- || (serviceState.mPendingPrepare)
|| (!serviceState.mPendingAppLinkInfo.isEmpty())
|| (!serviceState.mPendingAppLinkCommand.isEmpty());
@@ -1857,22 +1820,13 @@ public class TvInteractiveAppManagerService extends SystemService {
private final List<Pair<AppLinkInfo, Boolean>> mPendingAppLinkInfo = new ArrayList<>();
private final List<Bundle> mPendingAppLinkCommand = new ArrayList<>();
- private boolean mPendingPrepare = false;
- private Integer mPendingPrepareType = null;
private ITvInteractiveAppService mService;
private ServiceCallback mCallback;
private boolean mBound;
private boolean mReconnecting;
private ServiceState(ComponentName component, String tias, int userId) {
- this(component, tias, userId, false, null);
- }
-
- private ServiceState(ComponentName component, String tias, int userId,
- boolean pendingPrepare, Integer prepareType) {
mComponent = component;
- mPendingPrepare = pendingPrepare;
- mPendingPrepareType = prepareType;
mConnection = new InteractiveAppServiceConnection(component, userId);
mIAppServiceId = tias;
}
@@ -1920,19 +1874,6 @@ public class TvInteractiveAppManagerService extends SystemService {
}
}
- if (serviceState.mPendingPrepare) {
- final long identity = Binder.clearCallingIdentity();
- try {
- serviceState.mService.prepare(serviceState.mPendingPrepareType);
- serviceState.mPendingPrepare = false;
- serviceState.mPendingPrepareType = null;
- } catch (RemoteException e) {
- Slogf.e(TAG, "error in prepare when onServiceConnected", e);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
if (!serviceState.mPendingAppLinkInfo.isEmpty()) {
for (Iterator<Pair<AppLinkInfo, Boolean>> it =
serviceState.mPendingAppLinkInfo.iterator();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 736732029510..f5ace6c78288 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -128,7 +128,6 @@ import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY;
import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA;
import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
import static com.android.server.wm.DisplayContentProto.SLEEP_TOKENS;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
@@ -5001,10 +5000,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// docked divider while keeping the app itself below the docked divider, so instead
// we will put the docked divider below the IME. @see #assignRelativeLayerForImeTargetChild
//
- // In the case the IME target is animating, the animation Z order may be different
- // than the WindowContainer Z order, so it's difficult to be sure we have the correct
- // IME target. In this case we just layer the IME over its parent surface.
- //
// In the case where we have no IME target we let its window parent to place it.
//
// Keep IME window in surface parent as long as app's starting window
@@ -5020,9 +5015,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// We don't need to set relative layer if the IME target in non-multi-window
// mode is the activity main window since updateImeParent will ensure the IME
// surface be attached on the fullscreen activity.
- && imeTarget.mAttrs.type != TYPE_BASE_APPLICATION
- && imeTarget.mToken.getActivity(app -> app.isAnimating(TRANSITION | PARENTS,
- ANIMATION_TYPE_ALL & ~ANIMATION_TYPE_RECENTS)) == null;
+ && imeTarget.mAttrs.type != TYPE_BASE_APPLICATION;
if (canImeTargetSetRelativeLayer) {
mImeWindowsContainer.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
// TODO: We need to use an extra level on the app surface to ensure
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 3951c567e89c..9844cb5fe8f8 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -344,7 +344,6 @@ class InsetsPolicy {
// Navigation bar doesn't get influenced by anything else
if (type == ITYPE_NAVIGATION_BAR || type == ITYPE_EXTRA_NAVIGATION_BAR) {
- state.removeSource(ITYPE_IME);
state.removeSource(ITYPE_STATUS_BAR);
state.removeSource(ITYPE_CLIMATE_BAR);
state.removeSource(ITYPE_CAPTION_BAR);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index ec0ecd44cda5..edfd6ed5f63d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -177,7 +177,7 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables){}
@Override
- public void resetDrawables(@NonNull String[] drawableIds){}
+ public void resetDrawables(@NonNull List<String> drawableIds){}
@Override
public ParcelableResource getDrawable(
@@ -189,7 +189,7 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public void setStrings(@NonNull List<DevicePolicyStringResource> strings){}
@Override
- public void resetStrings(String[] stringIds){}
+ public void resetStrings(@NonNull List<String> stringIds){}
@Override
public ParcelableResource getString(String stringId) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
index e70c071183ce..6f0330e97482 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
@@ -176,11 +176,11 @@ class DeviceManagementResourcesProvider {
/**
* Returns {@code false} if no resources were removed.
*/
- boolean removeDrawables(@NonNull String[] drawableIds) {
+ boolean removeDrawables(@NonNull List<String> drawableIds) {
synchronized (mLock) {
boolean removed = false;
- for (int i = 0; i < drawableIds.length; i++) {
- String drawableId = drawableIds[i];
+ for (int i = 0; i < drawableIds.size(); i++) {
+ String drawableId = drawableIds.get(i);
removed |= mUpdatedDrawablesForStyle.remove(drawableId) != null
|| mUpdatedDrawablesForSource.remove(drawableId) != null;
}
@@ -265,11 +265,11 @@ class DeviceManagementResourcesProvider {
/**
* Returns {@code false} if no resources were removed.
*/
- boolean removeStrings(@NonNull String[] stringIds) {
+ boolean removeStrings(@NonNull List<String> stringIds) {
synchronized (mLock) {
boolean removed = false;
- for (int i = 0; i < stringIds.length; i++) {
- String stringId = stringIds[i];
+ for (int i = 0; i < stringIds.size(); i++) {
+ String stringId = stringIds.get(i);
removed |= mUpdatedStrings.remove(stringId) != null;
}
if (!removed) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1d422a802ede..e6b57e052293 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2124,7 +2124,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
+ "profile: %d", doUserId, poUserId);
Slogf.i(LOG_TAG, "Giving the PO additional power...");
- markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId);
+ setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId, true);
Slogf.i(LOG_TAG, "Migrating DO policies to PO...");
moveDoPoliciesToProfileParentAdminLocked(doAdmin, poAdmin.getParentActiveAdmin());
migratePersonalAppSuspensionLocked(doUserId, poUserId, poAdmin);
@@ -14774,7 +14774,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public void markProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId) {
+ public void setProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId,
+ boolean isProfileOwnerOnOrganizationOwnedDevice) {
if (!mHasFeature) {
return;
}
@@ -14806,13 +14807,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Grant access under lock.
synchronized (getLockObject()) {
- markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(who, userId);
+ setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(who, userId,
+ isProfileOwnerOnOrganizationOwnedDevice);
}
}
@GuardedBy("getLockObject()")
- private void markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(
- ComponentName who, int userId) {
+ private void setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(
+ ComponentName who, int userId, boolean isProfileOwnerOnOrganizationOwnedDevice) {
// Make sure that the user has a profile owner and that the specified
// component is the profile owner of that user.
if (!isProfileOwner(who, userId)) {
@@ -14821,7 +14823,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
who.flattenToString(), userId));
}
- Slogf.i(LOG_TAG, "Marking %s as profile owner on organization-owned device for user %d",
+ Slogf.i(LOG_TAG, "%s %s as profile owner on organization-owned device for user %d",
+ isProfileOwnerOnOrganizationOwnedDevice ? "Marking" : "Unmarking",
who.flattenToString(), userId);
// First, set restriction on removing the profile.
@@ -14838,15 +14841,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
+ " on user %d", parentUser.getIdentifier()));
}
- mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true,
+ mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+ isProfileOwnerOnOrganizationOwnedDevice,
parentUser);
- mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true,
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER,
+ isProfileOwnerOnOrganizationOwnedDevice,
parentUser);
});
- // markProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
+ // setProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
// data, no need to do it manually.
- mOwners.markProfileOwnerOfOrganizationOwnedDevice(userId);
+ mOwners.setProfileOwnerOfOrganizationOwnedDevice(userId,
+ isProfileOwnerOnOrganizationOwnedDevice);
}
private void pushMeteredDisabledPackagesLocked(int userId) {
@@ -17783,7 +17789,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (provisioningParams.isOrganizationOwnedProvisioning()) {
synchronized (getLockObject()) {
- markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id);
+ setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id,
+ true);
}
}
@@ -18713,13 +18720,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderWithCleanCallingIdentity(() -> {
if (mDeviceManagementResourcesProvider.updateDrawables(drawables)) {
sendDrawableUpdatedBroadcast(
- drawables.stream().map(s -> s.getDrawableId()).toArray(String[]::new));
+ drawables.stream().map(s -> s.getDrawableId()).collect(
+ Collectors.toList()));
}
});
}
@Override
- public void resetDrawables(@NonNull String[] drawableIds) {
+ public void resetDrawables(@NonNull List<String> drawableIds) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
@@ -18740,7 +18748,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
drawableId, drawableStyle, drawableSource));
}
- private void sendDrawableUpdatedBroadcast(String[] drawableIds) {
+ private void sendDrawableUpdatedBroadcast(List<String> drawableIds) {
sendResourceUpdatedBroadcast(EXTRA_RESOURCE_TYPE_DRAWABLE, drawableIds);
}
@@ -18754,12 +18762,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderWithCleanCallingIdentity(() -> {
if (mDeviceManagementResourcesProvider.updateStrings(strings))
sendStringsUpdatedBroadcast(
- strings.stream().map(s -> s.getStringId()).toArray(String[]::new));
+ strings.stream().map(s -> s.getStringId()).collect(Collectors.toList()));
});
}
@Override
- public void resetStrings(String[] stringIds) {
+ public void resetStrings(@NonNull List<String> stringIds) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
@@ -18776,13 +18784,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mDeviceManagementResourcesProvider.getString(stringId));
}
- private void sendStringsUpdatedBroadcast(String[] stringIds) {
+ private void sendStringsUpdatedBroadcast(List<String> stringIds) {
sendResourceUpdatedBroadcast(EXTRA_RESOURCE_TYPE_STRING, stringIds);
}
- private void sendResourceUpdatedBroadcast(int resourceType, String[] resourceIds) {
+ private void sendResourceUpdatedBroadcast(int resourceType, List<String> resourceIds) {
final Intent intent = new Intent(ACTION_DEVICE_POLICY_RESOURCE_UPDATED);
- intent.putExtra(EXTRA_RESOURCE_IDS, resourceIds);
+ intent.putExtra(EXTRA_RESOURCE_IDS, resourceIds.toArray(String[]::new));
intent.putExtra(EXTRA_RESOURCE_TYPE, resourceType);
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index e1d720ca25c8..1fa2f53bea17 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -340,7 +340,7 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
private int runMarkProfileOwnerOnOrganizationOwnedDevice(PrintWriter pw) {
parseArgs(/* canHaveName= */ false);
- mService.markProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId);
+ mService.setProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId, true);
pw.printf("Success\n");
return 0;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index fe8f2235ed63..b0fdd723347f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -620,18 +620,15 @@ class Owners {
}
}
- /**
- * Sets the indicator that the profile owner manages an organization-owned device,
- * then write to file.
- */
- void markProfileOwnerOfOrganizationOwnedDevice(int userId) {
+ /** Set whether the profile owner manages an organization-owned device, then write to file. */
+ void setProfileOwnerOfOrganizationOwnedDevice(int userId, boolean isOrganizationOwnedDevice) {
synchronized (mLock) {
OwnerInfo profileOwner = mProfileOwners.get(userId);
if (profileOwner != null) {
- profileOwner.isOrganizationOwnedDevice = true;
+ profileOwner.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
} else {
Slog.e(TAG, String.format(
- "No profile owner for user %d to set as org-owned.", userId));
+ "No profile owner for user %d to set org-owned flag.", userId));
}
writeProfileOwner(userId);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
index eab96c09a00a..c17347320f52 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
@@ -72,9 +72,11 @@ public class BiometricSchedulerOperationTest {
@Mock
private ClientMonitorCallback mClientCallback;
@Mock
+ private ClientMonitorCallback mOnStartCallback;
+ @Mock
private FakeHal mHal;
@Captor
- ArgumentCaptor<ClientMonitorCallback> mStartCallback;
+ ArgumentCaptor<ClientMonitorCallback> mStartedCallbackCaptor;
private Handler mHandler;
private BiometricSchedulerOperation mOperation;
@@ -91,17 +93,17 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(cookie);
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- assertThat(mOperation.isReadyToStart()).isEqualTo(cookie);
+ assertThat(mOperation.isReadyToStart(mOnStartCallback)).isEqualTo(cookie);
assertThat(mOperation.isStarted()).isFalse();
assertThat(mOperation.isCanceling()).isFalse();
assertThat(mOperation.isFinished()).isFalse();
+ verify(mClientMonitor).waitForCookie(any());
- final boolean started = mOperation.startWithCookie(
- mock(ClientMonitorCallback.class), cookie);
+ final boolean started = mOperation.startWithCookie(mOnStartCallback, cookie);
assertThat(started).isTrue();
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
assertThat(mOperation.isStarted()).isTrue();
}
@@ -112,14 +114,15 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(goodCookie);
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- assertThat(mOperation.isReadyToStart()).isEqualTo(goodCookie);
- final boolean started = mOperation.startWithCookie(
- mock(ClientMonitorCallback.class), badCookie);
+ assertThat(mOperation.isReadyToStart(mOnStartCallback)).isEqualTo(goodCookie);
+ final boolean started = mOperation.startWithCookie(mOnStartCallback, badCookie);
assertThat(started).isFalse();
assertThat(mOperation.isStarted()).isFalse();
assertThat(mOperation.isCanceling()).isFalse();
assertThat(mOperation.isFinished()).isFalse();
+ verify(mClientMonitor).waitForCookie(any());
+ verify(mClientMonitor, never()).start(any());
}
@Test
@@ -127,26 +130,25 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(0);
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final ClientMonitorCallback cb = mock(ClientMonitorCallback.class);
- mOperation.start(cb);
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
+ mOperation.start(mOnStartCallback);
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
assertThat(mOperation.isStarted()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
assertThat(mOperation.isFinished()).isFalse();
verify(mClientCallback).onClientStarted(eq(mClientMonitor));
- verify(cb).onClientStarted(eq(mClientMonitor));
+ verify(mOnStartCallback).onClientStarted(eq(mClientMonitor));
verify(mClientCallback, never()).onClientFinished(any(), anyBoolean());
- verify(cb, never()).onClientFinished(any(), anyBoolean());
+ verify(mOnStartCallback, never()).onClientFinished(any(), anyBoolean());
- mStartCallback.getValue().onClientFinished(mClientMonitor, true);
+ mStartedCallbackCaptor.getValue().onClientFinished(mClientMonitor, true);
assertThat(mOperation.isFinished()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
verify(mClientMonitor).destroy();
- verify(cb).onClientFinished(eq(mClientMonitor), eq(true));
+ verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(true));
}
@Test
@@ -154,8 +156,7 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(0);
when(mClientMonitor.getFreshDaemon()).thenReturn(null);
- final ClientMonitorCallback cb = mock(ClientMonitorCallback.class);
- mOperation.start(cb);
+ mOperation.start(mOnStartCallback);
verify(mClientMonitor, never()).start(any());
assertThat(mOperation.isStarted()).isFalse();
@@ -163,9 +164,9 @@ public class BiometricSchedulerOperationTest {
assertThat(mOperation.isFinished()).isTrue();
verify(mClientCallback, never()).onClientStarted(eq(mClientMonitor));
- verify(cb, never()).onClientStarted(eq(mClientMonitor));
+ verify(mOnStartCallback, never()).onClientStarted(eq(mClientMonitor));
verify(mClientCallback).onClientFinished(eq(mClientMonitor), eq(false));
- verify(cb).onClientFinished(eq(mClientMonitor), eq(false));
+ verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
}
@Test
@@ -179,7 +180,7 @@ public class BiometricSchedulerOperationTest {
public void cannotRestart() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- mOperation.start(mock(ClientMonitorCallback.class));
+ mOperation.start(mOnStartCallback);
assertThrows(IllegalStateException.class,
() -> mOperation.start(mock(ClientMonitorCallback.class)));
@@ -202,7 +203,7 @@ public class BiometricSchedulerOperationTest {
public void cannotAbortRunning() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- mOperation.start(mock(ClientMonitorCallback.class));
+ mOperation.start(mOnStartCallback);
assertThrows(IllegalStateException.class, () -> mOperation.abort());
}
@@ -211,11 +212,10 @@ public class BiometricSchedulerOperationTest {
public void cancel() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final ClientMonitorCallback startCb = mock(ClientMonitorCallback.class);
final ClientMonitorCallback cancelCb = mock(ClientMonitorCallback.class);
- mOperation.start(startCb);
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
+ mOperation.start(mOnStartCallback);
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
mOperation.cancel(mHandler, cancelCb);
assertThat(mOperation.isCanceling()).isTrue();
@@ -223,7 +223,7 @@ public class BiometricSchedulerOperationTest {
verify(mClientMonitor, never()).cancelWithoutStarting(any());
verify(mClientMonitor, never()).destroy();
- mStartCallback.getValue().onClientFinished(mClientMonitor, true);
+ mStartedCallbackCaptor.getValue().onClientFinished(mClientMonitor, true);
assertThat(mOperation.isFinished()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
@@ -315,12 +315,10 @@ public class BiometricSchedulerOperationTest {
private void cancelWatchdog(boolean start) {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final ClientMonitorCallback opStartCallback = mock(ClientMonitorCallback.class);
- mOperation.start(opStartCallback);
+ mOperation.start(mOnStartCallback);
if (start) {
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
- verify(opStartCallback).onClientStarted(eq(mClientMonitor));
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
}
mOperation.cancel(mHandler, mock(ClientMonitorCallback.class));
@@ -331,7 +329,7 @@ public class BiometricSchedulerOperationTest {
assertThat(mOperation.isFinished()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
- verify(opStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
+ verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
verify(mClientMonitor).destroy();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 0fa2b41e8b32..45e3b4373266 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -196,7 +196,8 @@ public class BiometricSchedulerTest {
// Schedule a BiometricPrompt authentication request
mScheduler.scheduleClientMonitor(client1, callback1);
- assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart());
+ assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart(
+ mock(ClientMonitorCallback.class)));
assertEquals(client1, mScheduler.mCurrentOperation.getClientMonitor());
assertEquals(0, mScheduler.mPendingOperations.size());
@@ -436,7 +437,8 @@ public class BiometricSchedulerTest {
if (started || isEnroll) { // prep'd auth clients and enroll clients
assertTrue(mScheduler.mCurrentOperation.isStarted());
} else {
- assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart());
+ assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart(
+ mock(ClientMonitorCallback.class)));
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
index dc39b6d573db..5012335b533f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.hardware.biometrics.BiometricOverlayConstants;
import android.hardware.fingerprint.ISidefpsController;
@@ -29,6 +30,7 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
@@ -43,6 +45,7 @@ import java.util.List;
public class SensorOverlaysTest {
private static final int SENSOR_ID = 11;
+ private static final long REQUEST_ID = 8;
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
@@ -50,6 +53,12 @@ public class SensorOverlaysTest {
@Mock private ISidefpsController mSidefpsController;
@Mock private AcquisitionClient<?> mAcquisitionClient;
+ @Before
+ public void setup() {
+ when(mAcquisitionClient.getRequestId()).thenReturn(REQUEST_ID);
+ when(mAcquisitionClient.hasRequestId()).thenReturn(true);
+ }
+
@Test
public void noopWhenBothNull() {
final SensorOverlays useless = new SensorOverlays(null, null);
@@ -92,7 +101,8 @@ public class SensorOverlaysTest {
sensorOverlays.show(SENSOR_ID, reason, mAcquisitionClient);
if (udfps != null) {
- verify(mUdfpsOverlayController).showUdfpsOverlay(eq(SENSOR_ID), eq(reason), any());
+ verify(mUdfpsOverlayController).showUdfpsOverlay(
+ eq(REQUEST_ID), eq(SENSOR_ID), eq(reason), any());
}
if (sidefps != null) {
verify(mSidefpsController).show(eq(SENSOR_ID), eq(reason));
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
index 52eee9a55cc7..8391914a0bb6 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
@@ -18,9 +18,8 @@ package com.android.server.biometrics.sensors;
import static android.testing.TestableLooper.RunWithLooper;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -45,11 +44,15 @@ import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Supplier;
@Presubmit
@@ -61,9 +64,12 @@ public class UserAwareBiometricSchedulerTest {
private static final String TAG = "UserAwareBiometricSchedulerTest";
private static final int TEST_SENSOR_ID = 0;
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
private Handler mHandler;
private UserAwareBiometricScheduler mScheduler;
- private IBinder mToken = new Binder();
+ private final IBinder mToken = new Binder();
@Mock
private Context mContext;
@@ -74,15 +80,14 @@ public class UserAwareBiometricSchedulerTest {
@Mock
private BiometricContext mBiometricContext;
- private TestUserStartedCallback mUserStartedCallback = new TestUserStartedCallback();
- private TestUserStoppedCallback mUserStoppedCallback = new TestUserStoppedCallback();
+ private final TestUserStartedCallback mUserStartedCallback = new TestUserStartedCallback();
+ private final TestUserStoppedCallback mUserStoppedCallback = new TestUserStoppedCallback();
private int mCurrentUserId = UserHandle.USER_NULL;
private boolean mStartOperationsFinish = true;
private int mStartUserClientCount = 0;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
mHandler = new Handler(TestableLooper.get(this).getLooper());
mScheduler = new UserAwareBiometricScheduler(TAG,
mHandler,
@@ -121,8 +126,8 @@ public class UserAwareBiometricSchedulerTest {
mScheduler.scheduleClientMonitor(nextClient);
waitForIdle();
- assertEquals(0, mUserStoppedCallback.numInvocations);
- assertEquals(1, mUserStartedCallback.numInvocations);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+ assertThat(mUserStartedCallback.mStartedUsers).containsExactly(0);
verify(nextClient).start(any());
}
@@ -142,9 +147,9 @@ public class UserAwareBiometricSchedulerTest {
waitForIdle();
}
- assertEquals(0, mUserStoppedCallback.numInvocations);
- assertEquals(0, mUserStartedCallback.numInvocations);
- assertEquals(1, mStartUserClientCount);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+ assertThat(mUserStartedCallback.mStartedUsers).isEmpty();
+ assertThat(mStartUserClientCount).isEqualTo(1);
for (BaseClientMonitor client : nextClients) {
verify(client, never()).start(any());
}
@@ -163,13 +168,13 @@ public class UserAwareBiometricSchedulerTest {
final TestStartUserClient startUserClient =
(TestStartUserClient) mScheduler.mCurrentOperation.getClientMonitor();
mScheduler.reset();
- assertNull(mScheduler.mCurrentOperation);
+ assertThat(mScheduler.mCurrentOperation).isNull();
final BiometricSchedulerOperation fakeOperation = new BiometricSchedulerOperation(
mock(BaseClientMonitor.class), new ClientMonitorCallback() {});
mScheduler.mCurrentOperation = fakeOperation;
startUserClient.mCallback.onClientFinished(startUserClient, true);
- assertSame(fakeOperation, mScheduler.mCurrentOperation);
+ assertThat(fakeOperation).isSameInstanceAs(mScheduler.mCurrentOperation);
}
@Test
@@ -184,8 +189,8 @@ public class UserAwareBiometricSchedulerTest {
waitForIdle();
verify(nextClient).start(any());
- assertEquals(0, mUserStoppedCallback.numInvocations);
- assertEquals(0, mUserStartedCallback.numInvocations);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+ assertThat(mUserStartedCallback.mStartedUsers).isEmpty();
}
@Test
@@ -199,36 +204,67 @@ public class UserAwareBiometricSchedulerTest {
mScheduler.scheduleClientMonitor(nextClient);
waitForIdle();
- assertEquals(1, mUserStoppedCallback.numInvocations);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(1);
waitForIdle();
- assertEquals(1, mUserStartedCallback.numInvocations);
+ assertThat(mUserStartedCallback.mStartedUsers).containsExactly(nextUserId);
waitForIdle();
verify(nextClient).start(any());
}
+ @Test
+ public void testStartUser_alwaysStartsNextOperation() {
+ BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(10);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+
+ // finish first operation
+ mScheduler.getInternalCallback().onClientFinished(nextClient, true /* success */);
+ waitForIdle();
+
+ // schedule second operation but swap out the current operation
+ // before it runs so that it's not current when it's completion callback runs
+ nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(11);
+ mUserStartedCallback.mAfterStart = () -> mScheduler.mCurrentOperation = null;
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+ assertThat(mUserStartedCallback.mStartedUsers).containsExactly(10, 11).inOrder();
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(1);
+ }
+
private void waitForIdle() {
TestableLooper.get(this).processAllMessages();
}
private class TestUserStoppedCallback implements StopUserClient.UserStoppedCallback {
- int numInvocations;
+ int mNumInvocations;
@Override
public void onUserStopped() {
- numInvocations++;
+ mNumInvocations++;
mCurrentUserId = UserHandle.USER_NULL;
}
}
private class TestUserStartedCallback implements StartUserClient.UserStartedCallback<Object> {
- int numInvocations;
+ final List<Integer> mStartedUsers = new ArrayList<>();
+ Runnable mAfterStart = null;
@Override
public void onUserStarted(int newUserId, Object newObject, int halInterfaceVersion) {
- numInvocations++;
+ mStartedUsers.add(newUserId);
mCurrentUserId = newUserId;
+ if (mAfterStart != null) {
+ mAfterStart.run();
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index de0f038e8ec5..6c50ca35be79 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -71,6 +71,7 @@ public class FingerprintAuthenticationClientTest {
private static final int USER_ID = 8;
private static final long OP_ID = 7;
+ private static final long REQUEST_ID = 88;
private static final int POINTER_ID = 0;
private static final int TOUCH_X = 8;
private static final int TOUCH_Y = 20;
@@ -259,7 +260,7 @@ public class FingerprintAuthenticationClientTest {
client.start(mCallback);
- verify(mUdfpsOverlayController).showUdfpsOverlay(anyInt(), anyInt(), any());
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
verify(mSideFpsController).show(anyInt(), anyInt());
block.accept(client);
@@ -277,7 +278,7 @@ public class FingerprintAuthenticationClientTest {
final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
return new FingerprintAuthenticationClient(mContext, () -> aidl, mToken,
- 2 /* requestId */, mClientMonitorCallbackConverter, 5 /* targetUserId */, OP_ID,
+ REQUEST_ID, mClientMonitorCallbackConverter, 5 /* targetUserId */, OP_ID,
false /* restricted */, "test-owner", 4 /* cookie */, false /* requireConfirmation */,
9 /* sensorId */, mBiometricLogger, mBiometricContext,
true /* isStrongBiometric */,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index 5a96f5cca52a..f77eb0bcc59f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -72,6 +72,7 @@ public class FingerprintEnrollClientTest {
private static final byte[] HAT = new byte[69];
private static final int USER_ID = 8;
+ private static final long REQUEST_ID = 9;
private static final int POINTER_ID = 0;
private static final int TOUCH_X = 8;
private static final int TOUCH_Y = 20;
@@ -256,7 +257,7 @@ public class FingerprintEnrollClientTest {
client.start(mCallback);
- verify(mUdfpsOverlayController).showUdfpsOverlay(anyInt(), anyInt(), any());
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
verify(mSideFpsController).show(anyInt(), anyInt());
block.accept(client);
@@ -273,7 +274,7 @@ public class FingerprintEnrollClientTest {
when(mHal.getInterfaceVersion()).thenReturn(version);
final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
- return new FingerprintEnrollClient(mContext, () -> aidl, mToken, 6 /* requestId */,
+ return new FingerprintEnrollClient(mContext, () -> aidl, mToken, REQUEST_ID,
mClientMonitorCallbackConverter, 0 /* userId */,
HAT, "owner", mBiometricUtils, 8 /* sensorId */,
mBiometricLogger, mBiometricContext, mSensorProps, mUdfpsOverlayController,
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 8438afcfe5e4..a2409b8bef0f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -6665,7 +6665,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mContext, false);
assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin2));
+ () -> dpm.setProfileOwnerOnOrganizationOwnedDevice(admin2, true));
}
@Test
@@ -6674,7 +6674,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mContext, false);
assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1));
+ () -> dpm.setProfileOwnerOnOrganizationOwnedDevice(admin1, true));
}
@Test
@@ -6709,7 +6709,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
DpmMockContext.CALLER_MANAGED_PROVISIONING_UID);
try {
runAsCaller(mServiceContext, dpms, dpm -> {
- dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1);
+ dpm.setProfileOwnerOnOrganizationOwnedDevice(admin1, true);
});
} finally {
mServiceContext.binder.restoreCallingIdentity(ident);
@@ -7044,7 +7044,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mServiceContext, true);
runAsCaller(mServiceContext, dpms, dpm -> {
- dpm.markProfileOwnerOnOrganizationOwnedDevice(who);
+ dpm.setProfileOwnerOnOrganizationOwnedDevice(who, true);
});
mServiceContext.binder.restoreCallingIdentity(ident);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 99edecfeed30..c78678431dac 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -16,7 +16,6 @@
package com.android.server.pm;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundlesEqual;
-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertEmpty;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
@@ -37,6 +36,8 @@ import android.app.Person;
import android.content.ComponentName;
import android.content.Intent;
import android.content.LocusId;
+import android.content.pm.Capability;
+import android.content.pm.CapabilityParams;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
import android.graphics.BitmapFactory;
@@ -258,10 +259,15 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
.setLongLived(true)
.setExtras(pb)
.setStartingTheme(android.R.style.Theme_Black_NoTitleBar_Fullscreen)
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.type", list("running", "jogging"))
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.duration", list("10m"))
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging")
+ .build())
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m")
+ .build())
.build();
si.addFlags(ShortcutInfo.FLAG_PINNED);
si.setBitmapPath("abc");
@@ -299,13 +305,14 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertEquals(null, si.getDisabledMessageResName());
assertEquals("android:style/Theme.Black.NoTitleBar.Fullscreen",
si.getStartingThemeResName());
- assertTrue(si.hasCapability("action.intent.START_EXERCISE"));
- assertFalse(si.hasCapability(""));
- assertFalse(si.hasCapability("random"));
- assertEquals(list("running", "jogging"), si.getCapabilityParameterValues(
- "action.intent.START_EXERCISE", "exercise.type"));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", ""));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", "random"));
+ assertEquals(list(new Capability.Builder("action.intent.START_EXERCISE").build()),
+ si.getCapabilities());
+ assertEquals(list(
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m").build()),
+ si.getCapabilityParams(
+ new Capability.Builder("action.intent.START_EXERCISE").build()));
}
public void testShortcutInfoParcel_resId() {
@@ -959,10 +966,15 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
.setRank(123)
.setExtras(pb)
.setLocusId(new LocusId("1.2.3.4.5"))
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.type", list("running", "jogging"))
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.duration", list("10m"))
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging")
+ .build())
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m")
+ .build())
.build();
sorig.setTimestamp(mInjectedCurrentTimeMillis);
@@ -1024,13 +1036,14 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertNull(si.getIconUri());
assertTrue(si.getLastChangedTimestamp() < now);
- assertTrue(si.hasCapability("action.intent.START_EXERCISE"));
- assertFalse(si.hasCapability(""));
- assertFalse(si.hasCapability("random"));
- assertEquals(list("running", "jogging"), si.getCapabilityParameterValues(
- "action.intent.START_EXERCISE", "exercise.type"));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", ""));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", "random"));
+ assertEquals(list(new Capability.Builder("action.intent.START_EXERCISE").build()),
+ si.getCapabilities());
+ assertEquals(list(
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m").build()),
+ si.getCapabilityParams(
+ new Capability.Builder("action.intent.START_EXERCISE").build()));
// Make sure ranks are saved too. Because of the auto-adjusting, we need two shortcuts
// to test it.
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index b9abbf09e74d..93c03865dc3f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2015,7 +2015,7 @@ public class UsageStatsService extends SystemService implements
== PackageManager.PERMISSION_GRANTED;
}
- private boolean hasPermissions(String callingPackage, String... permissions) {
+ private boolean hasPermissions(String... permissions) {
final int callingUid = Binder.getCallingUid();
if (callingUid == Process.SYSTEM_UID) {
// Caller is the system, so proceed.
@@ -2578,7 +2578,7 @@ public class UsageStatsService extends SystemService implements
String callingPackage) {
final int callingUid = Binder.getCallingUid();
final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
- if (!hasPermissions(callingPackage,
+ if (!hasPermissions(
Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
&& (dpmInternal == null || !dpmInternal.isActiveSupervisionApp(callingUid))) {
throw new SecurityException("Caller must be the active supervision app or "
@@ -2605,7 +2605,7 @@ public class UsageStatsService extends SystemService implements
public void unregisterAppUsageLimitObserver(int observerId, String callingPackage) {
final int callingUid = Binder.getCallingUid();
final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
- if (!hasPermissions(callingPackage,
+ if (!hasPermissions(
Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
&& (dpmInternal == null || !dpmInternal.isActiveSupervisionApp(callingUid))) {
throw new SecurityException("Caller must be the active supervision app or "
@@ -2703,8 +2703,7 @@ public class UsageStatsService extends SystemService implements
@Override
public long getLastTimeAnyComponentUsed(String packageName, String callingPackage) {
- if (!hasPermissions(
- callingPackage, android.Manifest.permission.INTERACT_ACROSS_USERS)) {
+ if (!hasPermissions(android.Manifest.permission.INTERACT_ACROSS_USERS)) {
throw new SecurityException("Caller doesn't have INTERACT_ACROSS_USERS permission");
}
if (!hasPermission(callingPackage)) {
@@ -2787,6 +2786,17 @@ public class UsageStatsService extends SystemService implements
"clearBroadcastResponseStats" /* name */, callingPackage);
mResponseStatsTracker.clearBroadcastEvents(callingUid, userId);
}
+
+ @Override
+ @Nullable
+ public String getAppStandbyConstant(@NonNull String key) {
+ Objects.requireNonNull(key);
+
+ if (!hasPermissions(Manifest.permission.READ_DEVICE_CONFIG)) {
+ throw new SecurityException("Caller doesn't have READ_DEVICE_CONFIG permission");
+ }
+ return mAppStandby.getAppStandbyConstant(key);
+ }
}
void registerAppUsageObserver(int callingUid, int observerId, String[] packages,
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 398889213ce5..d527a230a97b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
import static android.Manifest.permission.RECORD_AUDIO;
import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_EXTERNAL;
import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_MICROPHONE;
+import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_SUCCESS;
import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_UNKNOWN;
import static android.service.voice.HotwordDetectionService.KEY_INITIALIZATION_STATUS;
@@ -330,15 +331,16 @@ final class HotwordDetectionConnection {
return new Pair<>(INITIALIZATION_STATUS_UNKNOWN, METRICS_INIT_UNKNOWN_NO_VALUE);
}
int status = bundle.getInt(KEY_INITIALIZATION_STATUS, INITIALIZATION_STATUS_UNKNOWN);
- if (status > HotwordDetectionService.getMaxCustomInitializationStatus()
- && status != INITIALIZATION_STATUS_UNKNOWN) {
+ if (status > HotwordDetectionService.getMaxCustomInitializationStatus()) {
return new Pair<>(INITIALIZATION_STATUS_UNKNOWN,
- METRICS_INIT_UNKNOWN_OVER_MAX_CUSTOM_VALUE);
+ status == INITIALIZATION_STATUS_UNKNOWN
+ ? METRICS_INIT_UNKNOWN_NO_VALUE
+ : METRICS_INIT_UNKNOWN_OVER_MAX_CUSTOM_VALUE);
}
// TODO: should guard against negative here
- int metricsResult = status == INITIALIZATION_STATUS_UNKNOWN
- ? METRICS_INIT_CALLBACK_STATE_ERROR
- : METRICS_INIT_CALLBACK_STATE_SUCCESS;
+ int metricsResult = status == INITIALIZATION_STATUS_SUCCESS
+ ? METRICS_INIT_CALLBACK_STATE_SUCCESS
+ : METRICS_INIT_CALLBACK_STATE_ERROR;
return new Pair<>(status, metricsResult);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3f430ab77df4..f3139a70eade 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9815,15 +9815,7 @@ public class TelephonyManager {
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @Nullable String getCarrierServicePackageName() {
- // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the
- // value instead of re-querying every time.
- List<String> carrierServicePackages =
- getCarrierPackageNamesForIntent(
- new Intent(CarrierService.CARRIER_SERVICE_INTERFACE));
- if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) {
- return carrierServicePackages.get(0);
- }
- return null;
+ return getCarrierServicePackageNameForLogicalSlot(getPhoneId());
}
/**
@@ -9840,13 +9832,15 @@ public class TelephonyManager {
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @Nullable String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) {
- // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the
- // value instead of re-querying every time.
- List<String> carrierServicePackages =
- getCarrierPackageNamesForIntentAndPhone(
- new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), logicalSlotIndex);
- if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) {
- return carrierServicePackages.get(0);
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getCarrierServicePackageNameForLogicalSlot(logicalSlotIndex);
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getCarrierServicePackageNameForLogicalSlot RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "getCarrierServicePackageNameForLogicalSlot NPE", ex);
}
return null;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a5e2c1f83939..e3ebb9a23950 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2541,4 +2541,15 @@ interface ITelephony {
* PhoneAccount#CAPABILITY_VOICE_CALLING_AVAILABLE.
*/
void setVoiceServiceStateOverride(int subId, boolean hasService, String callingPackage);
+
+ /**
+ * Returns the package name that provides the {@link CarrierService} implementation for the
+ * specified {@code logicalSlotIndex}, or {@code null} if no package with carrier privileges
+ * declares one.
+ *
+ * @param logicalSlotIndex The slot index to fetch the {@link CarrierService} package for
+ * @return The system-selected package that provides the {@link CarrierService} implementation
+ * for the slot, or {@code null} if none is resolved
+ */
+ String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex);
}