summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-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.txt71
-rw-r--r--core/api/system-current.txt12
-rw-r--r--core/api/test-current.txt5
-rw-r--r--core/java/Android.bp8
-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/TEST_MAPPING19
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java167
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl9
-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.aidl (renamed from core/java/com/android/internal/logging/UiEvent.java)18
-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/PackageInfo.java3
-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/inputmethodservice/NavigationBarController.java4
-rw-r--r--core/java/android/inputmethodservice/navigationbar/DeadZone.java2
-rw-r--r--core/java/android/inputmethodservice/navigationbar/KeyButtonView.java6
-rw-r--r--core/java/android/net/SntpClient.java9
-rw-r--r--core/java/android/os/storage/IStorageManager.aidl1
-rw-r--r--core/java/android/permission/PermissionUsageHelper.java15
-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/service/voice/AlwaysOnHotwordDetector.java6
-rw-r--r--core/java/android/util/NtpTrustedTime.java31
-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/logging/InstanceId.java98
-rw-r--r--core/java/com/android/internal/logging/InstanceIdSequence.java62
-rw-r--r--core/java/com/android/internal/logging/UiEventLogger.java111
-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.xml9
-rw-r--r--core/tests/coretests/src/android/net/SntpClientTest.java3
-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--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java2
-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--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java30
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java25
-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/TvInputManager.java4
-rw-r--r--media/java/android/media/tv/TvView.java10
-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.aidl4
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl5
-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.aidl3
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl3
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppManager.java83
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppService.java108
-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.java121
-rw-r--r--packages/ConnectivityT/framework-t/Android.bp2
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java283
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl13
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl1
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl (renamed from packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl)6
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-or/strings.xml2
-rw-r--r--packages/SettingsLib/res/values/strings.xml17
-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/SettingsProvider/res/values-or/strings.xml2
-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/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/privacy/PrivacyDialogController.kt31
-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/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/privacy/PrivacyDialogControllerTest.kt92
-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--proto/src/metrics_constants/metrics_constants.proto6
-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/NetworkTimeUpdateService.java6
-rw-r--r--services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java13
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java17
-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/am/OomAdjuster.java8
-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/locales/TEST_MAPPING9
-rw-r--r--services/core/java/com/android/server/pm/Installer.java44
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java131
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java4
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java17
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java2
-rw-r--r--services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java103
-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.java10
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java12
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java77
-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
-rw-r--r--tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java6
-rw-r--r--tests/TrustTests/AndroidManifest.xml10
-rw-r--r--tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt3
-rw-r--r--tests/TrustTests/src/android/trust/test/LockUserTest.kt4
-rw-r--r--tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt124
-rw-r--r--tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt25
196 files changed, 4096 insertions, 1538 deletions
diff --git a/Android.bp b/Android.bp
index edaa11e3dc73..149b22355c58 100644
--- a/Android.bp
+++ b/Android.bp
@@ -329,6 +329,7 @@ java_defaults {
"modules-utils-preconditions",
"modules-utils-synchronous-result-receiver",
"modules-utils-os",
+ "modules-utils-uieventlogger-interface",
"framework-permission-aidl-java",
"spatializer-aidl-java",
"audiopolicy-types-aidl-java",
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 3f12b6ca7d64..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);
@@ -7707,6 +7709,7 @@ package android.app.admin {
field public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
field @Deprecated public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
field public static final String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
+ field public static final String EXTRA_PROVISIONING_USE_MOBILE_DATA = "android.app.extra.PROVISIONING_USE_MOBILE_DATA";
field public static final String EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY = "android.app.extra.PROVISIONING_WIFI_ANONYMOUS_IDENTITY";
field public static final String EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_CA_CERTIFICATE";
field public static final String EXTRA_PROVISIONING_WIFI_DOMAIN = "android.app.extra.PROVISIONING_WIFI_DOMAIN";
@@ -11245,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();
@@ -12306,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();
@@ -12321,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();
@@ -12346,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>);
@@ -22210,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";
@@ -22899,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();
@@ -22933,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);
@@ -23460,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;
}
@@ -23473,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);
}
@@ -26077,7 +26104,7 @@ package android.media.tv {
method public void onContentAllowed(String);
method public void onContentBlocked(String, android.media.tv.TvContentRating);
method public void onDisconnected(String);
- method public void onSignalStrength(@NonNull String, int);
+ method public void onSignalStrengthUpdated(@NonNull String, int);
method public void onTimeShiftStatusChanged(String, int);
method public void onTrackSelected(String, int, String);
method public void onTracksChanged(String, java.util.List<android.media.tv.TvTrackInfo>);
@@ -26112,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);
@@ -26135,6 +26161,7 @@ package android.media.tv.interactive {
field public static final String INTENT_KEY_BI_INTERACTIVE_APP_TYPE = "bi_interactive_app_type";
field public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri";
field public static final String INTENT_KEY_CHANNEL_URI = "channel_uri";
+ field public static final String INTENT_KEY_COMMAND_TYPE = "command_type";
field public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id";
field public static final String INTENT_KEY_TV_INPUT_ID = "tv_input_id";
field public static final int INTERACTIVE_APP_STATE_ERROR = 3; // 0x3
@@ -26163,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";
@@ -26184,6 +26210,7 @@ package android.media.tv.interactive {
public abstract static class TvInteractiveAppService.Session implements android.view.KeyEvent.Callback {
ctor public TvInteractiveAppService.Session(@NonNull android.content.Context);
+ method public boolean isMediaViewEnabled();
method @CallSuper public void layoutSurface(int, int, int, int);
method @CallSuper public final void notifyBiInteractiveAppCreated(@NonNull android.net.Uri, @Nullable String);
method @CallSuper public void notifySessionStateChanged(int, int);
@@ -26192,23 +26219,24 @@ 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);
method public boolean onKeyMultiple(int, int, @NonNull android.view.KeyEvent);
method public boolean onKeyUp(int, @NonNull android.view.KeyEvent);
- method public void onMediaViewSizeChanged(int, int);
+ method public void onMediaViewSizeChanged(@Px int, @Px int);
method public abstract void onRelease();
method public void onResetInteractiveApp();
method public abstract boolean onSetSurface(@Nullable android.view.Surface);
method public void onSetTeletextAppEnabled(boolean);
method public void onSignalStrength(int);
+ method public void onSigningResult(@NonNull String, @NonNull byte[]);
method public void onStartInteractiveApp();
method public void onStopInteractiveApp();
method public void onStreamVolume(float);
@@ -26227,6 +26255,7 @@ package android.media.tv.interactive {
method @CallSuper public void requestCurrentChannelLcn();
method @CallSuper public void requestCurrentChannelUri();
method @CallSuper public void requestCurrentTvInputId();
+ method @CallSuper public void requestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
method @CallSuper public void requestStreamVolume();
method @CallSuper public void requestTrackInfoList();
method @CallSuper public void sendPlaybackCommandRequest(@NonNull String, @Nullable android.os.Bundle);
@@ -26256,6 +26285,7 @@ package android.media.tv.interactive {
method public void createBiInteractiveApp(@NonNull android.net.Uri, @Nullable android.os.Bundle);
method public void destroyBiInteractiveApp(@NonNull String);
method public boolean dispatchUnhandledInputEvent(@NonNull android.view.InputEvent);
+ method @Nullable public android.media.tv.interactive.TvInteractiveAppView.OnUnhandledInputEventListener getOnUnhandledInputEventListener();
method public void onAttachedToWindow();
method public void onDetachedFromWindow();
method public void onLayout(boolean, int, int, int, int);
@@ -26268,6 +26298,7 @@ package android.media.tv.interactive {
method public void sendCurrentChannelLcn(int);
method public void sendCurrentChannelUri(@Nullable android.net.Uri);
method public void sendCurrentTvInputId(@Nullable String);
+ method public void sendSigningResult(@NonNull String, @NonNull byte[]);
method public void sendStreamVolume(float);
method public void sendTrackInfoList(@Nullable java.util.List<android.media.tv.TvTrackInfo>);
method public void setCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppView.TvInteractiveAppCallback);
@@ -26276,6 +26307,11 @@ package android.media.tv.interactive {
method public int setTvView(@Nullable android.media.tv.TvView);
method public void startInteractiveApp();
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";
}
public static interface TvInteractiveAppView.OnUnhandledInputEventListener {
@@ -26289,6 +26325,7 @@ package android.media.tv.interactive {
method public void onRequestCurrentChannelLcn(@NonNull String);
method public void onRequestCurrentChannelUri(@NonNull String);
method public void onRequestCurrentTvInputId(@NonNull String);
+ method public void onRequestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
method public void onRequestStreamVolume(@NonNull String);
method public void onRequestTrackInfoList(@NonNull String);
method public void onSetVideoBounds(@NonNull String, @NonNull android.graphics.Rect);
@@ -57926,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 d094f4bad511..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";
@@ -1079,6 +1080,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int checkProvisioningPrecondition(@NonNull String, @NonNull String);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void finalizeWorkProfileProvisioning(@NonNull android.os.UserHandle, @Nullable android.accounts.Account);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
@@ -1089,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();
@@ -1103,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();
@@ -1149,6 +1149,7 @@ package android.app.admin {
field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
field public static final String EXTRA_ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE = "android.app.extra.ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE";
field public static final String EXTRA_ROLE_HOLDER_STATE = "android.app.extra.ROLE_HOLDER_STATE";
+ field public static final String EXTRA_ROLE_HOLDER_UPDATE_RESULT_CODE = "android.app.extra.ROLE_HOLDER_UPDATE_RESULT_CODE";
field public static final int FLAG_SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
field public static final int FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
@@ -1162,6 +1163,7 @@ package android.app.admin {
field public static final String REQUIRED_APP_MANAGED_PROFILE = "android.app.REQUIRED_APP_MANAGED_PROFILE";
field public static final String REQUIRED_APP_MANAGED_USER = "android.app.REQUIRED_APP_MANAGED_USER";
field public static final int RESULT_DEVICE_OWNER_SET = 123; // 0x7b
+ field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED = 3; // 0x3
field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1; // 0x1
field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2; // 0x2
field public static final int RESULT_UPDATE_ROLE_HOLDER = 2; // 0x2
@@ -3413,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 d984abe457c9..a67d002cdddf 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -501,6 +501,7 @@ package android.app.admin {
method public void forceUpdateUserSetupComplete(int);
method @NonNull public java.util.Set<java.lang.String> getDefaultCrossProfilePackages();
method public int getDeviceOwnerType(@NonNull android.content.ComponentName);
+ method @Nullable public String getDevicePolicyManagementRoleHolderUpdaterPackage();
method @NonNull public java.util.Set<java.lang.String> getDisallowedSystemApps(@NonNull android.content.ComponentName, int, @NonNull String);
method public long getLastBugReportRequestTime();
method public long getLastNetworkLogRetrievalTime();
@@ -511,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);
@@ -520,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
@@ -2428,7 +2429,7 @@ package android.service.quicksettings {
package android.service.voice {
public class AlwaysOnHotwordDetector implements android.service.voice.HotwordDetector {
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[]);
+ method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[], @NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
}
public static final class AlwaysOnHotwordDetector.EventPayload.Builder {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index a5526bc66431..f081a439c49c 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -145,16 +145,16 @@ genrule {
out: ["com/android/internal/util/FrameworkStatsLog.java"],
}
+// Library that provides functionality to log UiEvents in framework space.
+// If this functionality is needed outside the framework, the interfaces library
+// can be re-used and a local implementation is needed.
java_library {
name: "uieventloggerlib",
srcs: [
- "com/android/internal/logging/UiEvent.java",
- "com/android/internal/logging/UiEventLogger.java",
"com/android/internal/logging/UiEventLoggerImpl.java",
- "com/android/internal/logging/InstanceId.java",
- "com/android/internal/logging/InstanceIdSequence.java",
":statslog-framework-java-gen",
],
+ static_libs: ["modules-utils-uieventlogger-interface"],
}
filegroup {
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/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 32207af22dc1..649f90442536 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -146,15 +146,6 @@
}
],
"file_patterns": ["(/|^)ContextImpl.java"]
- },
- {
- "file_patterns": ["(/|^)LocaleManager.java"],
- "name": "CtsLocaleManagerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
}
],
"presubmit-large": [
@@ -182,6 +173,16 @@
{
"file_patterns": ["(/|^)ActivityThreadTest.java"],
"name": "FrameworksCoreTests"
+ },
+ // TODO(b/225192026): Move back to presubmit after b/225192026 is fixed
+ {
+ "file_patterns": ["(/|^)LocaleManager.java"],
+ "name": "CtsLocaleManagerTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
]
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7269b0d91d02..223e5da5bc6d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -21,6 +21,7 @@ import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.Manifest.permission;
+import android.accounts.Account;
import android.annotation.CallbackExecutor;
import android.annotation.ColorInt;
import android.annotation.IntDef;
@@ -1623,14 +1624,26 @@ public class DevicePolicyManager {
"android.app.extra.PROVISIONING_SKIP_EDUCATION_SCREENS";
/**
- * A boolean extra indicating if mobile data should be used during NFC device owner provisioning
- * for downloading the mobile device management application. If {@link
- * #EXTRA_PROVISIONING_WIFI_SSID} is also specified, wifi network will be used instead.
+ * A boolean extra indicating if mobile data should be used during the provisioning flow
+ * for downloading the admin app. If {@link #EXTRA_PROVISIONING_WIFI_SSID} is also specified,
+ * wifi network will be used instead.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
- * provisioning via an NFC bump.
+ * <p>Default value is {@code false}.
*
- * @hide
+ * <p>If this extra is set to {@code true} and {@link #EXTRA_PROVISIONING_WIFI_SSID} is not
+ * specified, this extra has different behaviour depending on the way provisioning is triggered:
+ * <ul>
+ * <li>
+ * For provisioning started via a QR code or an NFC tag, mobile data is always used for
+ * downloading the admin app.
+ * </li>
+ * <li>
+ * For all other provisioning methods, a mobile data connection check is made at the start
+ * of provisioning. If mobile data is connected at that point, the admin app download will
+ * happen using mobile data. If mobile data is not connected at that point, the end-user
+ * will be asked to pick a wifi network and the admin app download will proceed over wifi.
+ * </li>
+ * </ul>
*/
public static final String EXTRA_PROVISIONING_USE_MOBILE_DATA =
"android.app.extra.PROVISIONING_USE_MOBILE_DATA";
@@ -3283,9 +3296,11 @@ public class DevicePolicyManager {
* <p>The activity must handle the device policy management role holder update and set the
* intent result to either {@link Activity#RESULT_OK} if the update was successful, {@link
* #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it encounters a
- * problem that may be solved by relaunching it again, or {@link
- * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if it encounters a
- * problem that will not be solved by relaunching it again.
+ * problem that may be solved by relaunching it again, {@link
+ * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED} if role holder
+ * provisioning is disabled, or {@link
+ * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if it encounters
+ * any other problem that will not be solved by relaunching it again.
*
* <p>If this activity has additional internal conditions which are not met, it should return
* {@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR}.
@@ -3321,6 +3336,45 @@ public class DevicePolicyManager {
2;
/**
+ * Result code that can be returned by the {@link
+ * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} handler if role holder provisioning
+ * is disabled.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int
+ RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED = 3;
+
+ /**
+ * An {@code int} extra which contains the result code of the last attempt to update
+ * the device policy management role holder.
+ *
+ * <p>This extra is provided to the device policy management role holder via either {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} or {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_PROFILE} when started after the role holder
+ * had previously returned {@link #RESULT_UPDATE_ROLE_HOLDER}.
+ *
+ * <p>If the role holder update had failed, the role holder can use the value of this extra to
+ * make a decision whether to fail the provisioning flow or to carry on with the older version
+ * of the role holder.
+ *
+ * <p>Possible values can be:
+ * <ul>
+ * <li>{@link Activity#RESULT_OK} if the update was successful
+ * <li>{@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it
+ * encounters a problem that may be solved by relaunching it again.
+ * <li>{@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if
+ * it encounters a problem that will not be solved by relaunching it again.
+ * </ul>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_ROLE_HOLDER_UPDATE_RESULT_CODE =
+ "android.app.extra.ROLE_HOLDER_UPDATE_RESULT_CODE";
+
+ /**
* An {@link Intent} extra which resolves to a custom user consent screen.
*
* <p>If this extra is provided to the device policy management role holder via either {@link
@@ -3340,6 +3394,16 @@ public class DevicePolicyManager {
* <li>General disclaimer relevant to the provisioning mode</li>
* </ul>
*
+ * <p>When this {@link Intent} is started, the following intent extras will be supplied:
+ * <ul>
+ * <li>{@link #EXTRA_PROVISIONING_DISCLAIMERS}</li>
+ * <li>{@link #EXTRA_PROVISIONING_MODE}</li>
+ * <li>{@link #EXTRA_PROVISIONING_LOCALE}</li>
+ * <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME}</li>
+ * <li>{@link #EXTRA_PROVISIONING_TIME_ZONE}</li>
+ * <li>{@link #EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS}</li>
+ * </ul>
+ *
* <p>If the custom consent screens are granted by the user {@link Activity#RESULT_OK} is
* returned, otherwise {@link Activity#RESULT_CANCELED} is returned. The device policy
* management role holder should ensure that the provisioning flow terminates immediately if
@@ -14009,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
*/
@@ -14029,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
*/
@@ -14044,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();
}
@@ -14800,6 +14866,28 @@ public class DevicePolicyManager {
}
/**
+ * Called when a managed profile has been provisioned.
+ *
+ * @throws SecurityException if the caller does not hold
+ * {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public void finalizeWorkProfileProvisioning(
+ @NonNull UserHandle managedProfileUser, @Nullable Account migratedAccount) {
+ Objects.requireNonNull(managedProfileUser, "managedProfileUser can't be null");
+ if (mService == null) {
+ throw new IllegalStateException("Could not find DevicePolicyManagerService");
+ }
+ try {
+ mService.finalizeWorkProfileProvisioning(managedProfileUser, migratedAccount);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* The localized error message to show to the end-user. If {@code null}, a generic error
* message will be shown.
*/
@@ -15264,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();
}
@@ -15573,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();
}
@@ -15586,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.
@@ -15598,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,
@@ -15649,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(
@@ -15737,9 +15819,28 @@ public class DevicePolicyManager {
*/
@Nullable
public String getDevicePolicyManagementRoleHolderPackage() {
- String deviceManagerConfig = mContext.getString(
+ String devicePolicyManagementConfig = mContext.getString(
com.android.internal.R.string.config_devicePolicyManagement);
- return extractPackageNameFromDeviceManagerConfig(deviceManagerConfig);
+ return extractPackageNameFromDeviceManagerConfig(devicePolicyManagementConfig);
+ }
+
+ /**
+ * Returns the package name of the device policy management role holder updater.
+ *
+ * <p>If the device policy management role holder updater is not configured for this device,
+ * returns {@code null}.
+ *
+ * @hide
+ */
+ @Nullable
+ @TestApi
+ public String getDevicePolicyManagementRoleHolderUpdaterPackage() {
+ String devicePolicyManagementUpdaterConfig = mContext.getString(
+ com.android.internal.R.string.config_devicePolicyManagementUpdater);
+ if (TextUtils.isEmpty(devicePolicyManagementUpdaterConfig)) {
+ return null;
+ }
+ return devicePolicyManagementUpdaterConfig;
}
/**
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index fb1ca41ccc56..64241aa3312f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -17,6 +17,7 @@
package android.app.admin;
+import android.accounts.Account;
import android.app.admin.DevicePolicyDrawableResource;
import android.app.admin.DevicePolicyStringResource;
import android.app.admin.ParcelableResource;
@@ -476,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);
@@ -528,6 +529,8 @@ interface IDevicePolicyManager {
UserHandle createAndProvisionManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage);
void provisionFullyManagedDevice(in FullyManagedDeviceProvisioningParams provisioningParams, in String callerPackage);
+ void finalizeWorkProfileProvisioning(in UserHandle managedProfileUser, in Account migratedAccount);
+
void setDeviceOwnerType(in ComponentName admin, in int deviceOwnerType);
int getDeviceOwnerType(in ComponentName admin);
@@ -549,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/com/android/internal/logging/UiEvent.java b/core/java/android/content/pm/Capability.aidl
index 0407b0704e80..df3b1be1ce31 100644
--- a/core/java/com/android/internal/logging/UiEvent.java
+++ b/core/java/android/content/pm/Capability.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -13,18 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.content.pm;
-package com.android.internal.logging;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-@Retention(SOURCE)
-@Target(FIELD)
-public @interface UiEvent {
- /** An explanation, suitable for Android analysts, of the UI event that this log represents. */
- String doc();
-}
+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/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index eefa63f5b8fa..f4de82946253 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -213,7 +213,8 @@ public class PackageInfo implements Parcelable {
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_PERMISSIONS} was set. Each value matches
* the corresponding entry in {@link #requestedPermissions}, and will have
- * the flag {@link #REQUESTED_PERMISSION_GRANTED} set as appropriate.
+ * the flags {@link #REQUESTED_PERMISSION_GRANTED} and
+ * {@link #REQUESTED_PERMISSION_NEVER_FOR_LOCATION} set as appropriate.
*/
public int[] requestedPermissionsFlags;
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/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 0f9075b498ae..03d11515c0a8 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -294,8 +294,8 @@ final class NavigationBarController {
dest.setTouchableInsets(
ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- // TODO(b/205803355): See if we can use View#OnLayoutChangeListener().
- // TODO(b/205803355): See if we can replace DecorView#mNavigationColorViewState.view
+ // TODO(b/215443343): See if we can use View#OnLayoutChangeListener().
+ // TODO(b/215443343): See if we can replace DecorView#mNavigationColorViewState.view
boolean zOrderChanged = false;
if (decor instanceof ViewGroup) {
ViewGroup decorGroup = (ViewGroup) decor;
diff --git a/core/java/android/inputmethodservice/navigationbar/DeadZone.java b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
index 4cfd8139d912..382b6b074962 100644
--- a/core/java/android/inputmethodservice/navigationbar/DeadZone.java
+++ b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
@@ -148,7 +148,7 @@ final class DeadZone {
if (DEBUG) {
Log.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
}
- //TODO(b/205803355): call mNavBarController.touchAutoDim(mDisplayId); here
+ //TODO(b/215443343): call mNavBarController.touchAutoDim(mDisplayId); here
int size = (int) getSize(event.getEventTime());
// In the vertical orientation consume taps along the left edge.
// In horizontal orientation consume taps along the top edge.
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
index cfdb6caab9d3..92d358fe1663 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
@@ -89,7 +89,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
public KeyButtonView(Context context, AttributeSet attrs) {
super(context, attrs);
- // TODO(b/205803355): Figure out better place to set this.
+ // TODO(b/215443343): Figure out better place to set this.
switch (getId()) {
case com.android.internal.R.id.input_method_nav_back:
mCode = KEYCODE_BACK;
@@ -285,11 +285,11 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
private void sendEvent(int action, int flags, long when) {
if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
if (action == MotionEvent.ACTION_UP) {
- // TODO(b/205803355): Implement notifyBackAction();
+ // TODO(b/215443343): Implement notifyBackAction();
}
}
- // TODO(b/205803355): Consolidate this logic to somewhere else.
+ // TODO(b/215443343): Consolidate this logic to somewhere else.
if (mContext instanceof InputMethodService) {
final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index 0eb4cf3ecadf..b05f7cf241e3 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -60,7 +60,7 @@ public class SntpClient {
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;
- private static final int NTP_PORT = 123;
+ public static final int STANDARD_NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_MODE_SERVER = 4;
private static final int NTP_MODE_BROADCAST = 5;
@@ -108,18 +108,21 @@ public class SntpClient {
* Sends an SNTP request to the given host and processes the response.
*
* @param host host name of the server.
+ * @param port port of the server.
* @param timeout network timeout in milliseconds. the timeout doesn't include the DNS lookup
* time, and it applies to each individual query to the resolved addresses of
* the NTP server.
* @param network network over which to send the request.
* @return true if the transaction was successful.
*/
- public boolean requestTime(String host, int timeout, Network network) {
+ public boolean requestTime(String host, int port, int timeout, Network network) {
final Network networkForResolv = network.getPrivateDnsBypassingCopy();
try {
final InetAddress[] addresses = networkForResolv.getAllByName(host);
for (int i = 0; i < addresses.length; i++) {
- if (requestTime(addresses[i], NTP_PORT, timeout, networkForResolv)) return true;
+ if (requestTime(addresses[i], port, timeout, networkForResolv)) {
+ return true;
+ }
}
} catch (UnknownHostException e) {
Log.w(TAG, "Unknown host: " + host);
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index c021c079ae2e..a0f6598640ba 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -125,7 +125,6 @@ interface IStorageManager {
boolean isUserKeyUnlocked(int userId) = 65;
void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 66;
void destroyUserStorage(in String volumeUuid, int userId, int flags) = 67;
- boolean isConvertibleToFBE() = 68;
void addUserKeyAuth(int userId, int serialNumber, in byte[] secret) = 70;
void fixateNewestUserKeyAuth(int userId) = 71;
void fstrim(int flags, IVoldTaskListener listener) = 72;
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 0b57842cde11..4ed939c48bd7 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -47,6 +47,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.icu.text.ListFormatter;
+import android.location.LocationManager;
import android.media.AudioManager;
import android.os.Process;
import android.os.UserHandle;
@@ -411,10 +412,13 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
}
/**
- * Returns true if the app supports subattribution.
+ * Returns true if the app satisfies subattribution policies and supports it
*/
private boolean isSubattributionSupported(String packageName, int uid) {
try {
+ if (!isLocationProvider(packageName)) {
+ return false;
+ }
PackageManager userPkgManager =
getUserContext(UserHandle.getUserHandleForUid(uid)).getPackageManager();
ApplicationInfo appInfo = userPkgManager.getApplicationInfoAsUser(packageName,
@@ -430,6 +434,15 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
}
/**
+ * @param packageName
+ * @return If the package is location provider
+ */
+ private boolean isLocationProvider(String packageName) {
+ return Objects.requireNonNull(
+ mContext.getSystemService(LocationManager.class)).isProviderPackage(packageName);
+ }
+
+ /**
* Get the raw usages from the system, and then parse out the ones that are not recent enough,
* determine which permission group each belongs in, and removes duplicates (if the same app
* uses multiple permissions of the same group). Stores the package name, attribution tag, user,
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/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index bec5d1be57fd..bc42da6b4c97 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -851,7 +851,8 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
public void triggerHardwareRecognitionEventForTest(int status, int soundModelHandle,
boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs,
- boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data) {
+ boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
+ @NonNull List<KeyphraseRecognitionExtra> keyphraseRecognitionExtras) {
Log.d(TAG, "triggerHardwareRecognitionEventForTest()");
synchronized (mLock) {
if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
@@ -862,7 +863,8 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
mModelManagementService.triggerHardwareRecognitionEventForTest(
new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable,
captureSession, captureDelayMs, capturePreambleMs, triggerInData,
- captureFormat, data, null /* keyphraseExtras */),
+ captureFormat, data, keyphraseRecognitionExtras.toArray(
+ new KeyphraseRecognitionExtra[0])),
mInternalCallback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index aebc5e86605a..01a037ae3495 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -140,6 +140,10 @@ public class NtpTrustedTime implements TrustedTime {
/** An in-memory config override for use during tests. */
@Nullable
+ private Integer mPortForTests;
+
+ /** An in-memory config override for use during tests. */
+ @Nullable
private Duration mTimeoutForTests;
// Declared volatile and accessed outside of synchronized blocks to avoid blocking reads during
@@ -163,9 +167,11 @@ public class NtpTrustedTime implements TrustedTime {
* Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
* test value, i.e. so the normal value will be used next time.
*/
- public void setServerConfigForTests(@Nullable String hostname, @Nullable Duration timeout) {
+ public void setServerConfigForTests(
+ @Nullable String hostname, @Nullable Integer port, @Nullable Duration timeout) {
synchronized (this) {
mHostnameForTests = hostname;
+ mPortForTests = port;
mTimeoutForTests = timeout;
}
}
@@ -195,8 +201,9 @@ public class NtpTrustedTime implements TrustedTime {
if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
final SntpClient client = new SntpClient();
final String serverName = connectionInfo.getServer();
+ final int port = connectionInfo.getPort();
final int timeoutMillis = connectionInfo.getTimeoutMillis();
- if (client.requestTime(serverName, timeoutMillis, network)) {
+ if (client.requestTime(serverName, port, timeoutMillis, network)) {
long ntpCertainty = client.getRoundTripTime() / 2;
mTimeResult = new TimeResult(
client.getNtpTime(), client.getNtpTimeReference(), ntpCertainty);
@@ -297,10 +304,12 @@ public class NtpTrustedTime implements TrustedTime {
private static class NtpConnectionInfo {
@NonNull private final String mServer;
+ private final int mPort;
private final int mTimeoutMillis;
- NtpConnectionInfo(@NonNull String server, int timeoutMillis) {
+ NtpConnectionInfo(@NonNull String server, int port, int timeoutMillis) {
mServer = Objects.requireNonNull(server);
+ mPort = port;
mTimeoutMillis = timeoutMillis;
}
@@ -309,6 +318,11 @@ public class NtpTrustedTime implements TrustedTime {
return mServer;
}
+ @NonNull
+ public int getPort() {
+ return mPort;
+ }
+
int getTimeoutMillis() {
return mTimeoutMillis;
}
@@ -317,6 +331,7 @@ public class NtpTrustedTime implements TrustedTime {
public String toString() {
return "NtpConnectionInfo{"
+ "mServer='" + mServer + '\''
+ + ", mPort='" + mPort + '\''
+ ", mTimeoutMillis=" + mTimeoutMillis
+ '}';
}
@@ -341,6 +356,13 @@ public class NtpTrustedTime implements TrustedTime {
}
}
+ final Integer port;
+ if (mPortForTests != null) {
+ port = mPortForTests;
+ } else {
+ port = SntpClient.STANDARD_NTP_PORT;
+ }
+
final int timeoutMillis;
if (mTimeoutForTests != null) {
timeoutMillis = (int) mTimeoutForTests.toMillis();
@@ -350,7 +372,8 @@ public class NtpTrustedTime implements TrustedTime {
timeoutMillis = Settings.Global.getInt(
resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis);
}
- return TextUtils.isEmpty(hostname) ? null : new NtpConnectionInfo(hostname, timeoutMillis);
+ return TextUtils.isEmpty(hostname) ? null :
+ new NtpConnectionInfo(hostname, port, timeoutMillis);
}
/** Prints debug information. */
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/logging/InstanceId.java b/core/java/com/android/internal/logging/InstanceId.java
deleted file mode 100644
index c90d851201a2..000000000000
--- a/core/java/com/android/internal/logging/InstanceId.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2020 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.internal.logging;
-
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * An opaque identifier used to disambiguate which logs refer to a particular instance of some
- * UI element. Useful when there might be multiple instances simultaneously active.
- * Obtain from InstanceIdSequence. Clipped to range [0, INSTANCE_ID_MAX].
- */
-public final class InstanceId implements Parcelable {
- // At most 20 bits: ~1m possibilities, ~0.5% probability of collision in 100 values
- static final int INSTANCE_ID_MAX = 1 << 20;
-
- private final int mId;
- InstanceId(int id) {
- mId = min(max(0, id), INSTANCE_ID_MAX);
- }
-
- private InstanceId(Parcel in) {
- this(in.readInt());
- }
-
- @VisibleForTesting
- public int getId() {
- return mId;
- }
-
- /**
- * Create a fake instance ID for testing purposes. Not for production use. See also
- * InstanceIdSequenceFake, which is a testing replacement for InstanceIdSequence.
- * @param id The ID you want to assign.
- * @return new InstanceId.
- */
- @VisibleForTesting
- public static InstanceId fakeInstanceId(int id) {
- return new InstanceId(id);
- }
-
- @Override
- public int hashCode() {
- return mId;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof InstanceId)) {
- return false;
- }
- return mId == ((InstanceId) obj).mId;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mId);
- }
-
- public static final Parcelable.Creator<InstanceId> CREATOR =
- new Parcelable.Creator<InstanceId>() {
- @Override
- public InstanceId createFromParcel(Parcel in) {
- return new InstanceId(in);
- }
-
- @Override
- public InstanceId[] newArray(int size) {
- return new InstanceId[size];
- }
- };
-
-}
diff --git a/core/java/com/android/internal/logging/InstanceIdSequence.java b/core/java/com/android/internal/logging/InstanceIdSequence.java
deleted file mode 100644
index 34643105b965..000000000000
--- a/core/java/com/android/internal/logging/InstanceIdSequence.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2020 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.internal.logging;
-
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.security.SecureRandom;
-import java.util.Random;
-
-/**
- * Generates random InstanceIds in range [1, instanceIdMax] for passing to
- * UiEventLogger.logWithInstanceId(). Holds a SecureRandom, which self-seeds on
- * first use; try to give it a long lifetime. Safe for concurrent use.
- */
-public class InstanceIdSequence {
- protected final int mInstanceIdMax;
- private final Random mRandom = new SecureRandom();
-
- /**
- * Constructs a sequence with identifiers [1, instanceIdMax]. Capped at INSTANCE_ID_MAX.
- * @param instanceIdMax Limiting value of identifiers. Normally positive: otherwise you get
- * an all-1 sequence.
- */
- public InstanceIdSequence(int instanceIdMax) {
- mInstanceIdMax = min(max(1, instanceIdMax), InstanceId.INSTANCE_ID_MAX);
- }
-
- /**
- * Gets the next instance from the sequence. Safe for concurrent use.
- * @return new InstanceId
- */
- public InstanceId newInstanceId() {
- return newInstanceIdInternal(1 + mRandom.nextInt(mInstanceIdMax));
- }
-
- /**
- * Factory function for instance IDs, used for testing.
- * @param id
- * @return new InstanceId(id)
- */
- @VisibleForTesting
- protected InstanceId newInstanceIdInternal(int id) {
- return new InstanceId(id);
- }
-}
diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java
deleted file mode 100644
index 5378b03fe1c5..000000000000
--- a/core/java/com/android/internal/logging/UiEventLogger.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 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.internal.logging;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-/**
- * Logging interface for UI events. Normal implementation is UiEventLoggerImpl.
- * For testing, use fake implementation UiEventLoggerFake.
- *
- * See go/sysui-event-logs and UiEventReported atom in atoms.proto.
- */
-public interface UiEventLogger {
- /** Put your Event IDs in enums that implement this interface, and document them using the
- * UiEventEnum annotation.
- * Event IDs must be globally unique. This will be enforced by tooling (forthcoming).
- * OEMs should use event IDs above 100000 and below 1000000 (1 million).
- */
- interface UiEventEnum {
-
- /**
- * Tag used to request new UI Event IDs via presubmit analysis.
- *
- * <p>Use RESERVE_NEW_UI_EVENT_ID as the constructor parameter for a new {@link EventEnum}
- * to signal the presubmit analyzer to reserve a new ID for the event. The new ID will be
- * returned as a Gerrit presubmit finding. Do not submit {@code RESERVE_NEW_UI_EVENT_ID} as
- * the constructor parameter for any event.
- *
- * <pre>
- * &#064;UiEvent(doc = "Briefly describe the interaction when this event will be logged")
- * UNIQUE_EVENT_NAME(RESERVE_NEW_UI_EVENT_ID);
- * </pre>
- */
- int RESERVE_NEW_UI_EVENT_ID = Integer.MIN_VALUE; // Negative IDs are ignored by the logger.
-
- int getId();
- }
-
- /**
- * Log a simple event, with no package information. Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- */
- void log(@NonNull UiEventEnum event);
-
- /**
- * Log a simple event with an instance id, without package information.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to log().
- */
- void log(@NonNull UiEventEnum event, @Nullable InstanceId instance);
-
- /**
- * Log an event with package information. Does nothing if event.getId() <= 0.
- * Give both uid and packageName if both are known, but one may be omitted if unknown.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- */
- void log(@NonNull UiEventEnum event, int uid, @Nullable String packageName);
-
- /**
- * Log an event with package information and an instance ID.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to log().
- */
- void logWithInstanceId(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
- @Nullable InstanceId instance);
-
- /**
- * Log an event with ranked-choice information along with package.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- * @param position the position picked.
- */
- void logWithPosition(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
- int position);
-
- /**
- * Log an event with ranked-choice information along with package and instance ID.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to
- * logWithPosition().
- * @param position the position picked.
- */
- void logWithInstanceIdAndPosition(@NonNull UiEventEnum event, int uid,
- @Nullable String packageName, @Nullable InstanceId instance, int position);
-}
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 d652b2ff4f4a..0c194db02128 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -528,6 +528,7 @@
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
+ <protected-broadcast android:name="android.app.action.MANAGED_PROFILE_PROVISIONED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
<protected-broadcast android:name="com.android.bluetooth.map.USER_CONFIRM_TIMEOUT" />
@@ -720,10 +721,12 @@
<!-- 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" />
<protected-broadcast android:name="android.app.action.PROVISIONING_COMPLETED" />
+ <protected-broadcast android:name="android.app.action.LOST_MODE_LOCATION_UPDATE" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
@@ -6051,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/net/SntpClientTest.java b/core/tests/coretests/src/android/net/SntpClientTest.java
index ba7df1e218d9..267fc2b636d6 100644
--- a/core/tests/coretests/src/android/net/SntpClientTest.java
+++ b/core/tests/coretests/src/android/net/SntpClientTest.java
@@ -295,7 +295,8 @@ public class SntpClientTest {
@Test
public void testDnsResolutionFailure() throws Exception {
- assertFalse(mClient.requestTime("ntp.server.doesnotexist.example", 5000, mNetwork));
+ assertFalse(mClient.requestTime("ntp.server.doesnotexist.example",
+ SntpClient.STANDARD_NTP_PORT, 5000, mNetwork));
}
@Test
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/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index ec45a016507a..625f52a87ecf 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -232,7 +232,7 @@ public final class LooperStatsTest {
assertThat(entry3.handlerClassName).isEqualTo(
"com.android.internal.os.LooperStatsTest$TestHandlerSecond");
assertThat(entry3.messageName).startsWith(
- "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda5");
+ "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda");
assertThat(entry3.messageCount).isEqualTo(1);
assertThat(entry3.recordedMessageCount).isEqualTo(1);
assertThat(entry3.exceptionCount).isEqualTo(0);
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/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index be713a59a816..e5a755c35add 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -166,8 +166,7 @@ public class PipTransition extends PipTransitionController {
mExitTransition = null;
mHasFadeOut = false;
if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(null, null);
- mFinishCallback = null;
+ callFinishCallback(null /* wct */);
mFinishTransaction = null;
throw new RuntimeException("Previous callback not called, aborting exit PIP.");
}
@@ -232,6 +231,11 @@ public class PipTransition extends PipTransitionController {
return false;
}
+ /** Helper to identify whether this handler is currently the one playing an animation */
+ private boolean isAnimatingLocally() {
+ return mFinishTransaction != null;
+ }
+
@Nullable
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@@ -282,9 +286,11 @@ public class PipTransition extends PipTransitionController {
if (enteringPip) {
mPipTransitionState.setTransitionState(ENTERED_PIP);
}
- // If there is an expected exit transition, then the exit will be "merged" into this
- // transition so don't fire the finish-callback in that case.
- if (mExitTransition == null && mFinishCallback != null) {
+ // If we have an exit transition, but aren't playing a transition locally, it
+ // means we're expecting the exit transition will be "merged" into another transition
+ // (likely a remote like launcher), so don't fire the finish-callback here -- wait until
+ // the exit transition is merged.
+ if ((mExitTransition == null || isAnimatingLocally()) && mFinishCallback != null) {
WindowContainerTransaction wct = new WindowContainerTransaction();
prepareFinishResizeTransaction(taskInfo, destinationBounds,
direction, wct);
@@ -305,12 +311,19 @@ public class PipTransition extends PipTransitionController {
mSurfaceTransactionHelper.crop(mFinishTransaction, leash, finishBounds);
}
mFinishTransaction = null;
- mFinishCallback.onTransitionFinished(wct, null /* callback */);
- mFinishCallback = null;
+ callFinishCallback(wct);
}
finishResizeForMenu(destinationBounds);
}
+ private void callFinishCallback(WindowContainerTransaction wct) {
+ // Need to unset mFinishCallback first because onTransitionFinished can re-enter this
+ // handler if there is a pending PiP animation.
+ final Transitions.TransitionFinishCallback finishCallback = mFinishCallback;
+ mFinishCallback = null;
+ finishCallback.onTransitionFinished(wct, null /* callback */);
+ }
+
@Override
public void forceFinishTransition() {
if (mFinishCallback == null) return;
@@ -572,8 +585,7 @@ public class PipTransition extends PipTransitionController {
mHasFadeOut = false;
if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
- mFinishCallback = null;
+ callFinishCallback(null /* wct */);
mFinishTransaction = null;
throw new RuntimeException("Previous callback not called, aborting entering PIP.");
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 177b4a8b5982..2da5becae8f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
@@ -325,8 +326,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
}
- public void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
- @Nullable Bundle options) {
+ public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
+ @SplitPosition int position, @Nullable Bundle options) {
if (!ENABLE_SHELL_TRANSITIONS) {
startIntentLegacy(intent, fillInIntent, position, options);
return;
@@ -335,6 +336,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
try {
options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
null /* wct */);
+
+ // Flag this as a no-user-action launch to prevent sending user leaving event to the
+ // current top activity since it's going to be put into another side of the split. This
+ // prevents the current top activity from going into pip mode due to user leaving event.
+ if (fillInIntent == null) {
+ fillInIntent = new Intent();
+ }
+ fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
+
intent.send(mContext, 0, fillInIntent, null /* onFinished */, null /* handler */,
null /* requiredPermission */, options);
} catch (PendingIntent.CanceledException e) {
@@ -342,7 +352,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
}
- private void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
+ private void startIntentLegacy(PendingIntent intent, @Nullable Intent fillInIntent,
@SplitPosition int position, @Nullable Bundle options) {
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
mStageCoordinator.prepareEvictChildTasks(position, evictWct);
@@ -393,6 +403,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
final WindowContainerTransaction wct = new WindowContainerTransaction();
options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);
+
+ // Flag this as a no-user-action launch to prevent sending user leaving event to the current
+ // top activity since it's going to be put into another side of the split. This prevents the
+ // current top activity from going into pip mode due to user leaving event.
+ if (fillInIntent == null) {
+ fillInIntent = new Intent();
+ }
+ fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
+
wct.sendPendingIntent(intent, fillInIntent, options);
mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
}
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/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 69fe5ee49872..149c2f471a4c 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -680,7 +680,7 @@ public final class TvInputManager {
* @param session A {@link TvInputManager.Session} associated with this callback.
* @param strength The current signal strength.
*/
- public void onSignalStrength(Session session, @SignalStrength int strength) {
+ public void onSignalStrengthUpdated(Session session, @SignalStrength int strength) {
}
/**
@@ -898,7 +898,7 @@ public final class TvInputManager {
mHandler.post(new Runnable() {
@Override
public void run() {
- mSessionCallback.onSignalStrength(mSession, strength);
+ mSessionCallback.onSignalStrengthUpdated(mSession, strength);
if (mSession.mIAppNotificationEnabled
&& mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifySignalStrength(strength);
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 4d63af7be474..ff3d06c5bd69 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -1083,7 +1083,7 @@ public class TvView extends ViewGroup {
* @param inputId The ID of the TV input bound to this view.
* @param strength The current signal strength.
*/
- public void onSignalStrength(
+ public void onSignalStrengthUpdated(
@NonNull String inputId, @TvInputManager.SignalStrength int strength) {
}
@@ -1406,16 +1406,16 @@ public class TvView extends ViewGroup {
}
@Override
- public void onSignalStrength(Session session, int strength) {
+ public void onSignalStrengthUpdated(Session session, int strength) {
if (DEBUG) {
- Log.d(TAG, "onSignalStrength(strength=" + strength + ")");
+ Log.d(TAG, "onSignalStrengthUpdated(strength=" + strength + ")");
}
if (this != mSessionCallback) {
- Log.w(TAG, "onSignalStrength - session not created");
+ Log.w(TAG, "onSignalStrengthUpdated - session not created");
return;
}
if (mCallback != null) {
- mCallback.onSignalStrength(mInputId, strength);
+ mCallback.onSignalStrengthUpdated(mInputId, strength);
}
}
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 a3e58d16f655..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.
@@ -44,5 +44,7 @@ oneway interface ITvInteractiveAppClient {
void onRequestStreamVolume(int seq);
void onRequestTrackInfoList(int seq);
void onRequestCurrentTvInputId(int seq);
+ void onRequestSigning(
+ in String id, in String algorithm, in String alias, in byte[] data, int seq);
void onAdRequest(in AdRequest request, int Seq);
}
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index 839118265732..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);
@@ -50,6 +49,8 @@ interface ITvInteractiveAppManager {
void sendStreamVolume(in IBinder sessionToken, float volume, int userId);
void sendTrackInfoList(in IBinder sessionToken, in List<TvTrackInfo> tracks, int userId);
void sendCurrentTvInputId(in IBinder sessionToken, in String inputId, int userId);
+ void sendSigningResult(in IBinder sessionToken, in String signingId, in byte[] result,
+ int userId);
void createSession(in ITvInteractiveAppClient client, in String iAppServiceId, int type,
int seq, int userId);
void releaseSession(in IBinder sessionToken, 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 c449d2475428..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.
@@ -42,6 +42,7 @@ oneway interface ITvInteractiveAppSession {
void sendStreamVolume(float volume);
void sendTrackInfoList(in List<TvTrackInfo> tracks);
void sendCurrentTvInputId(in String inputId);
+ void sendSigningResult(in String signingId, in byte[] result);
void release();
void notifyTuned(in Uri channelUri);
void notifyTrackSelected(int type, in String trackId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index 385f0d4f766a..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.
@@ -43,5 +43,6 @@ oneway interface ITvInteractiveAppSessionCallback {
void onRequestStreamVolume();
void onRequestTrackInfoList();
void onRequestCurrentTvInputId();
+ void onRequestSigning(in String id, in String algorithm, in String alias, in byte[] data);
void onAdRequest(in AdRequest request);
}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index 83ff0f50f1a3..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.
@@ -28,7 +28,6 @@ import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvContentRating;
-import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.media.tv.TvTrackInfo;
import android.net.Uri;
@@ -249,7 +248,7 @@ public final class TvInteractiveAppManager {
*
* @see #sendAppLinkCommand(String, Bundle)
* @see #ACTION_APP_LINK_COMMAND
- * @see android.media.tv.interactive.TvInteractiveAppServiceInfo#getId()
+ * @see TvInteractiveAppServiceInfo#getId()
*/
public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id";
@@ -285,6 +284,16 @@ public final class TvInteractiveAppManager {
*/
public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri";
+ /**
+ * Intent key for command type. It's used to send app command to TV app. The value of this key
+ * could vary according to TV apps.
+ * <p>Type: String
+ *
+ * @see #sendAppLinkCommand(String, Bundle)
+ * @see #ACTION_APP_LINK_COMMAND
+ */
+ public static final String INTENT_KEY_COMMAND_TYPE = "command_type";
+
private final ITvInteractiveAppManager mService;
private final int mUserId;
@@ -478,6 +487,19 @@ public final class TvInteractiveAppManager {
}
@Override
+ public void onRequestSigning(
+ String id, String algorithm, String alias, byte[] data, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postRequestSigning(id, algorithm, alias, data);
+ }
+ }
+
+ @Override
public void onSessionStateChanged(int state, int err, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -752,22 +774,11 @@ public final class TvInteractiveAppManager {
}
/**
- * Prepares TV Interactive App service environment for the given type.
- */
- public void prepare(@NonNull String tvIAppServiceId, 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.
*
* @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
- * ID can be found in {@link TvInputInfo#getId()}.
+ * ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
* @param appLinkInfo The Android application link info record to be registered.
*/
public void registerAppLinkInfo(
@@ -784,7 +795,7 @@ public final class TvInteractiveAppManager {
* Android application by TV interactive App RTE.
*
* @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
- * ID can be found in {@link TvInputInfo#getId()}.
+ * ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
* @param appLinkInfo The Android application link info record to be unregistered.
*/
public void unregisterAppLinkInfo(
@@ -800,7 +811,7 @@ public final class TvInteractiveAppManager {
* Sends app link command.
*
* @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
- * ID can be found in {@link TvInputInfo#getId()}.
+ * ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
* @param command The command to be sent.
*/
public void sendAppLinkCommand(@NonNull String tvIAppServiceId, @NonNull Bundle command) {
@@ -1024,6 +1035,18 @@ public final class TvInteractiveAppManager {
}
}
+ void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.sendSigningResult(mToken, signingId, result, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Sets the {@link android.view.Surface} for this session.
*
@@ -1657,6 +1680,15 @@ public final class TvInteractiveAppManager {
});
}
+ void postRequestSigning(String id, String algorithm, String alias, byte[] data) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onRequestSigning(mSession, id, algorithm, alias, data);
+ }
+ });
+ }
+
void postAdRequest(final AdRequest request) {
mHandler.post(new Runnable() {
@Override
@@ -1794,12 +1826,27 @@ public final class TvInteractiveAppManager {
* called.
*
* @param session A {@link TvInteractiveAppService.Session} associated with this callback.
- * @hide
*/
public void onRequestCurrentTvInputId(Session session) {
}
/**
+ * This is called when
+ * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} is
+ * called.
+ *
+ * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
+ * @param signingId the ID to identify the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc.
+ * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+ * @param data the original bytes to be signed.
+ */
+ public void onRequestSigning(
+ Session session, String signingId, String algorithm, String alias, byte[] data) {
+ }
+
+ /**
* This is called when {@link TvInteractiveAppService.Session#notifySessionStateChanged} is
* called.
*
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 316fbbab6d37..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.
@@ -20,6 +20,7 @@ import android.annotation.CallSuper;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Px;
import android.annotation.SdkConstant;
import android.annotation.StringDef;
import android.annotation.SuppressLint;
@@ -217,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);
}
@@ -240,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) {
@@ -373,6 +364,15 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
+ * Returns {@code true} if media view is enabled, {@code false} otherwise.
+ *
+ * @see #setMediaViewEnabled(boolean)
+ */
+ public boolean isMediaViewEnabled() {
+ return mMediaViewEnabled;
+ }
+
+ /**
* Starts TvInteractiveAppService session.
*/
public void onStartInteractiveApp() {
@@ -397,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) {
}
@@ -407,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) {
}
/**
@@ -435,6 +436,8 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Receives current stream volume.
+ *
+ * @param volume a volume value between {@code 0.0f} and {@code 1.0f}, inclusive.
*/
public void onStreamVolume(float volume) {
}
@@ -452,6 +455,17 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
+ * Receives signing result.
+ * @param signingId the ID to identify the request. It's the same as the corresponding ID in
+ * {@link Session#requestSigning(String, String, String, byte[])}
+ * @param result the signed result.
+ *
+ * @see #requestSigning(String, String, String, byte[])
+ */
+ public void onSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ }
+
+ /**
* Called when the application sets the surface.
*
* <p>The TV Interactive App service should render interactive app UI onto the given
@@ -484,10 +498,10 @@ public abstract class TvInteractiveAppService extends Service {
* containing {@link TvInteractiveAppView}. Note that the size of the underlying surface can
* be different if the surface was changed by calling {@link #layoutSurface}.
*
- * @param width The width of the media view.
- * @param height The height of the media view.
+ * @param width The width of the media view, in pixels.
+ * @param height The height of the media view, in pixels.
*/
- public void onMediaViewSizeChanged(int width, int height) {
+ public void onMediaViewSizeChanged(@Px int width, @Px int height) {
}
/**
@@ -877,6 +891,47 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
+ * Requests signing of the given data.
+ *
+ * <p>This is used when the corresponding server of the broadcast-independent interactive
+ * app requires signing during handshaking, and the interactive app service doesn't have
+ * the built-in private key. The private key is provided by the content providers and
+ * pre-built in the related app, such as TV app.
+ *
+ * @param signingId the ID to identify the request. When a result is received, this ID can
+ * be used to correlate the result with the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc. The name is from standards like
+ * FIPS PUB 186-4 and PKCS #1.
+ * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+ * @param data the original bytes to be signed.
+ *
+ * @see #onSigningResult(String, byte[])
+ * @see TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
+ * @see TvInteractiveAppView#BI_INTERACTIVE_APP_KEY_ALIAS
+ */
+ @CallSuper
+ public void requestSigning(@NonNull String signingId, @NonNull String algorithm,
+ @NonNull String alias, @NonNull byte[] data) {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "requestSigning");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onRequestSigning(signingId, algorithm, alias, data);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in requestSigning", e);
+ }
+ }
+ });
+ }
+
+ /**
* Sends an advertisement request to be processed by the related TV input.
*
* @param request The advertisement request
@@ -914,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) {
@@ -945,6 +1000,10 @@ public abstract class TvInteractiveAppService extends Service {
onCurrentTvInputId(inputId);
}
+ void sendSigningResult(String signingId, byte[] result) {
+ onSigningResult(signingId, result);
+ }
+
void release() {
onRelease();
if (mSurface != null) {
@@ -1074,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(
@@ -1413,6 +1472,11 @@ public abstract class TvInteractiveAppService extends Service {
}
@Override
+ public void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ mSessionImpl.sendSigningResult(signingId, result);
+ }
+
+ @Override
public void release() {
mSessionImpl.scheduleMediaViewCleanup();
mSessionImpl.release();
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 9c1b2425c013..4370f7097268 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 212051120e77..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.
@@ -46,6 +46,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
+import java.security.KeyStore;
import java.util.List;
import java.util.concurrent.Executor;
@@ -61,6 +62,41 @@ public class TvInteractiveAppView extends ViewGroup {
private static final int UNSET_TVVIEW_SUCCESS = 3;
private static final int UNSET_TVVIEW_FAIL = 4;
+ /**
+ * Used to share client {@link java.security.cert.Certificate} with
+ * {@link TvInteractiveAppService}.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ * @see java.security.cert.Certificate
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_CERTIFICATE = "certificate";
+ /**
+ * Used to share the {@link KeyStore} alias with {@link TvInteractiveAppService}.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ * @see KeyStore#aliases()
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias";
+ /**
+ * Used to share the {@link java.security.PrivateKey} with {@link TvInteractiveAppService}.
+ * <p>The private key is optional. It is used to encrypt data when necessary.
+ *
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ * @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();
private final Object mCallbackLock = new Object();
@@ -242,7 +278,9 @@ public class TvInteractiveAppView extends ViewGroup {
}
/**
- * Resets this TvInteractiveAppView.
+ * Resets this TvInteractiveAppView to release its resources.
+ *
+ * <p>It can be reused by call {@link #prepareInteractiveApp(String, int)}.
*/
public void reset() {
if (DEBUG) Log.d(TAG, "reset()");
@@ -368,6 +406,19 @@ public class TvInteractiveAppView extends ViewGroup {
mOnUnhandledInputEventListener = listener;
// TODO: handle CallbackExecutor
}
+
+ /**
+ * Gets the {@link OnUnhandledInputEventListener}.
+ * <p>Returns {@code null} if the listener is not set or is cleared.
+ *
+ * @see #setOnUnhandledInputEventListener(Executor, OnUnhandledInputEventListener)
+ * @see #clearOnUnhandledInputEventListener()
+ */
+ @Nullable
+ public OnUnhandledInputEventListener getOnUnhandledInputEventListener() {
+ return mOnUnhandledInputEventListener;
+ }
+
/**
* Clears the {@link OnUnhandledInputEventListener}.
*/
@@ -390,7 +441,8 @@ public class TvInteractiveAppView extends ViewGroup {
}
/**
- * Prepares the interactive application.
+ * Prepares the interactive application runtime environment of corresponding
+ * {@link TvInteractiveAppService}.
*
* @param iAppServiceId the interactive app service ID, which can be found in
* {@link TvInteractiveAppServiceInfo#getId()}.
@@ -436,6 +488,8 @@ public class TvInteractiveAppView extends ViewGroup {
/**
* Resets the interactive application.
+ *
+ * <p>This releases the resources of the corresponding {@link TvInteractiveAppService.Session}.
*/
public void resetInteractiveApp() {
if (DEBUG) {
@@ -475,6 +529,8 @@ public class TvInteractiveAppView extends ViewGroup {
/**
* Sends stream volume to related TV interactive app.
+ *
+ * @param volume a volume value between {@code 0.0f} and {@code 1.0f}, inclusive.
*/
public void sendStreamVolume(float volume) {
if (DEBUG) {
@@ -513,6 +569,27 @@ public class TvInteractiveAppView extends ViewGroup {
}
}
+ /**
+ * Sends signing result to related TV interactive app.
+ *
+ * <p>This is used when the corresponding server of the broadcast-independent interactive
+ * app requires signing during handshaking, and the interactive app service doesn't have
+ * the built-in private key. The private key is provided by the content providers and
+ * pre-built in the related app, such as TV app.
+ *
+ * @param signingId the ID to identify the request. It's the same as the corresponding ID in
+ * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])}
+ * @param result the signed result.
+ */
+ public void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ if (DEBUG) {
+ Log.d(TAG, "sendSigningResult");
+ }
+ if (mSession != null) {
+ mSession.sendSigningResult(signingId, result);
+ }
+ }
+
private void resetInternal() {
mSessionCallback = null;
if (mSession != null) {
@@ -531,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) {
@@ -725,6 +809,22 @@ public class TvInteractiveAppView extends ViewGroup {
public void onRequestCurrentTvInputId(@NonNull String iAppServiceId) {
}
+ /**
+ * This is called when
+ * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} is
+ * called.
+ *
+ * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param signingId the ID to identify the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc.
+ * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+ * @param data the original bytes to be signed.
+ */
+ public void onRequestSigning(@NonNull String iAppServiceId, @NonNull String signingId,
+ @NonNull String algorithm, @NonNull String alias, @NonNull byte[] data) {
+ }
+
}
/**
@@ -1031,5 +1131,20 @@ public class TvInteractiveAppView extends ViewGroup {
mCallback.onRequestCurrentTvInputId(mIAppServiceId);
}
}
+
+ @Override
+ public void onRequestSigning(
+ Session session, String id, String algorithm, String alias, byte[] data) {
+ if (DEBUG) {
+ Log.d(TAG, "onRequestSigning");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onRequestSigning - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onRequestSigning(mIAppServiceId, id, algorithm, alias, data);
+ }
+ }
}
}
diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp
index 217a1f67c336..bc278528570f 100644
--- a/packages/ConnectivityT/framework-t/Android.bp
+++ b/packages/ConnectivityT/framework-t/Android.bp
@@ -131,8 +131,8 @@ filegroup {
"src/android/net/EthernetNetworkUpdateRequest.java",
"src/android/net/EthernetNetworkUpdateRequest.aidl",
"src/android/net/IEthernetManager.aidl",
- "src/android/net/IEthernetNetworkManagementListener.aidl",
"src/android/net/IEthernetServiceListener.aidl",
+ "src/android/net/INetworkInterfaceOutcomeReceiver.aidl",
"src/android/net/ITetheredInterfaceCallback.aidl",
],
path: "src",
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
index 793f28d5aa59..e02ea897dbe6 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
@@ -30,6 +30,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
+import android.os.OutcomeReceiver;
import android.os.RemoteException;
import com.android.internal.annotations.GuardedBy;
@@ -38,9 +39,10 @@ import com.android.modules.utils.BackgroundThread;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
+import java.util.function.IntConsumer;
/**
* A class that manages and configures Ethernet interfaces.
@@ -53,15 +55,31 @@ public class EthernetManager {
private static final String TAG = "EthernetManager";
private final IEthernetManager mService;
- @GuardedBy("mListeners")
- private final ArrayList<ListenerInfo> mListeners = new ArrayList<>();
+ @GuardedBy("mListenerLock")
+ private final ArrayList<ListenerInfo<InterfaceStateListener>> mIfaceListeners =
+ new ArrayList<>();
+ @GuardedBy("mListenerLock")
+ private final ArrayList<ListenerInfo<IntConsumer>> mEthernetStateListeners =
+ new ArrayList<>();
+ final Object mListenerLock = new Object();
private final IEthernetServiceListener.Stub mServiceListener =
new IEthernetServiceListener.Stub() {
@Override
+ public void onEthernetStateChanged(int state) {
+ synchronized (mListenerLock) {
+ for (ListenerInfo<IntConsumer> li : mEthernetStateListeners) {
+ li.executor.execute(() -> {
+ li.listener.accept(state);
+ });
+ }
+ }
+ }
+
+ @Override
public void onInterfaceStateChanged(String iface, int state, int role,
IpConfiguration configuration) {
- synchronized (mListeners) {
- for (ListenerInfo li : mListeners) {
+ synchronized (mListenerLock) {
+ for (ListenerInfo<InterfaceStateListener> li : mIfaceListeners) {
li.executor.execute(() ->
li.listener.onInterfaceStateChanged(iface, state, role,
configuration));
@@ -70,13 +88,29 @@ public class EthernetManager {
}
};
- private static class ListenerInfo {
+ /**
+ * Indicates that Ethernet is disabled.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int ETHERNET_STATE_DISABLED = 0;
+
+ /**
+ * Indicates that Ethernet is enabled.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int ETHERNET_STATE_ENABLED = 1;
+
+ private static class ListenerInfo<T> {
@NonNull
public final Executor executor;
@NonNull
- public final InterfaceStateListener listener;
+ public final T listener;
- private ListenerInfo(@NonNull Executor executor, @NonNull InterfaceStateListener listener) {
+ private ListenerInfo(@NonNull Executor executor, @NonNull T listener) {
this.executor = executor;
this.listener = listener;
}
@@ -289,16 +323,22 @@ public class EthernetManager {
if (listener == null || executor == null) {
throw new NullPointerException("listener and executor must not be null");
}
- synchronized (mListeners) {
- mListeners.add(new ListenerInfo(executor, listener));
- if (mListeners.size() == 1) {
- try {
- mService.addListener(mServiceListener);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ synchronized (mListenerLock) {
+ maybeAddServiceListener();
+ mIfaceListeners.add(new ListenerInfo<InterfaceStateListener>(executor, listener));
+ }
+ }
+
+ @GuardedBy("mListenerLock")
+ private void maybeAddServiceListener() {
+ if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return;
+
+ try {
+ mService.addListener(mServiceListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
+
}
/**
@@ -323,15 +363,20 @@ public class EthernetManager {
@SystemApi(client = MODULE_LIBRARIES)
public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) {
Objects.requireNonNull(listener);
- synchronized (mListeners) {
- mListeners.removeIf(l -> l.listener == listener);
- if (mListeners.isEmpty()) {
- try {
- mService.removeListener(mServiceListener);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ synchronized (mListenerLock) {
+ mIfaceListeners.removeIf(l -> l.listener == listener);
+ maybeRemoveServiceListener();
+ }
+ }
+
+ @GuardedBy("mListenerLock")
+ private void maybeRemoveServiceListener() {
+ if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return;
+
+ try {
+ mService.removeListener(mServiceListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -443,41 +488,45 @@ public class EthernetManager {
return new TetheredInterfaceRequest(mService, cbInternal);
}
- private static final class InternalNetworkManagementListener
- extends IEthernetNetworkManagementListener.Stub {
+ private static final class NetworkInterfaceOutcomeReceiver
+ extends INetworkInterfaceOutcomeReceiver.Stub {
@NonNull
private final Executor mExecutor;
@NonNull
- private final BiConsumer<Network, EthernetNetworkManagementException> mListener;
+ private final OutcomeReceiver<String, EthernetNetworkManagementException> mCallback;
- InternalNetworkManagementListener(
+ NetworkInterfaceOutcomeReceiver(
@NonNull final Executor executor,
- @NonNull final BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @NonNull final OutcomeReceiver<String, EthernetNetworkManagementException>
+ callback) {
Objects.requireNonNull(executor, "Pass a non-null executor");
- Objects.requireNonNull(listener, "Pass a non-null listener");
+ Objects.requireNonNull(callback, "Pass a non-null callback");
mExecutor = executor;
- mListener = listener;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onResult(@NonNull String iface) {
+ mExecutor.execute(() -> mCallback.onResult(iface));
}
@Override
- public void onComplete(
- @Nullable final Network network,
- @Nullable final EthernetNetworkManagementException e) {
- mExecutor.execute(() -> mListener.accept(network, e));
+ public void onError(@NonNull EthernetNetworkManagementException e) {
+ mExecutor.execute(() -> mCallback.onError(e));
}
}
- private InternalNetworkManagementListener getInternalNetworkManagementListener(
+ private NetworkInterfaceOutcomeReceiver makeNetworkInterfaceOutcomeReceiver(
@Nullable final Executor executor,
- @Nullable final BiConsumer<Network, EthernetNetworkManagementException> listener) {
- if (null != listener) {
- Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
+ @Nullable final OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
+ if (null != callback) {
+ Objects.requireNonNull(executor, "Pass a non-null executor, or a null callback");
}
- final InternalNetworkManagementListener proxy;
- if (null == listener) {
+ final NetworkInterfaceOutcomeReceiver proxy;
+ if (null == callback) {
proxy = null;
} else {
- proxy = new InternalNetworkManagementListener(executor, listener);
+ proxy = new NetworkInterfaceOutcomeReceiver(executor, callback);
}
return proxy;
}
@@ -492,14 +541,17 @@ public class EthernetManager {
* Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities}
* object for this network to put inside the {@code request}.
*
- * If non-null, the listener will be called exactly once after this is called, unless
- * a synchronous exception was thrown.
+ * This function accepts an {@link OutcomeReceiver} that is called once the operation has
+ * finished execution.
*
* @param iface the name of the interface to act upon.
* @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's
* {@link StaticIpConfiguration} and {@link NetworkCapabilities} values.
- * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
- * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+ * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+ * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+ * operation. On success, {@link OutcomeReceiver#onResult} is called with the
+ * interface name. On error, {@link OutcomeReceiver#onError} is called with more
+ * information about the error.
* @throws SecurityException if the process doesn't hold
* {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
* @throws UnsupportedOperationException if called on a non-automotive device or on an
@@ -515,11 +567,11 @@ public class EthernetManager {
@NonNull String iface,
@NonNull EthernetNetworkUpdateRequest request,
@Nullable @CallbackExecutor Executor executor,
- @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
Objects.requireNonNull(iface, "iface must be non-null");
Objects.requireNonNull(request, "request must be non-null");
- final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
- executor, listener);
+ final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+ executor, callback);
try {
mService.updateConfiguration(iface, request, proxy);
} catch (RemoteException e) {
@@ -528,20 +580,20 @@ public class EthernetManager {
}
/**
- * Set an ethernet network's link state up.
+ * Enable a network interface.
*
- * When the link is successfully turned up, the listener will be called with the resulting
- * network. If any error or unexpected condition happens while the system tries to turn the
- * interface up, the listener will be called with an appropriate exception.
- * The listener is guaranteed to be called exactly once for each call to this method, but this
- * may take an unbounded amount of time depending on the actual network conditions.
+ * Enables a previously disabled network interface.
+ * This function accepts an {@link OutcomeReceiver} that is called once the operation has
+ * finished execution.
*
- * @param iface the name of the interface to act upon.
- * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
- * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+ * @param iface the name of the interface to enable.
+ * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+ * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+ * operation. On success, {@link OutcomeReceiver#onResult} is called with the
+ * interface name. On error, {@link OutcomeReceiver#onError} is called with more
+ * information about the error.
* @throws SecurityException if the process doesn't hold
* {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
- * @throws UnsupportedOperationException if called on a non-automotive device.
* @hide
*/
@SystemApi
@@ -550,13 +602,13 @@ public class EthernetManager {
android.Manifest.permission.NETWORK_STACK,
android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
- public void connectNetwork(
+ public void enableInterface(
@NonNull String iface,
@Nullable @CallbackExecutor Executor executor,
- @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
Objects.requireNonNull(iface, "iface must be non-null");
- final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
- executor, listener);
+ final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+ executor, callback);
try {
mService.connectNetwork(iface, proxy);
} catch (RemoteException e) {
@@ -565,19 +617,21 @@ public class EthernetManager {
}
/**
- * Set an ethernet network's link state down.
+ * Disable a network interface.
*
- * When the link is successfully turned down, the listener will be called with the network that
- * was torn down, if any. If any error or unexpected condition happens while the system tries to
- * turn the interface down, the listener will be called with an appropriate exception.
- * The listener is guaranteed to be called exactly once for each call to this method.
+ * Disables the use of a network interface to fulfill network requests. If the interface
+ * currently serves a request, the network will be torn down.
+ * This function accepts an {@link OutcomeReceiver} that is called once the operation has
+ * finished execution.
*
- * @param iface the name of the interface to act upon.
- * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
- * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+ * @param iface the name of the interface to disable.
+ * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+ * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+ * operation. On success, {@link OutcomeReceiver#onResult} is called with the
+ * interface name. On error, {@link OutcomeReceiver#onError} is called with more
+ * information about the error.
* @throws SecurityException if the process doesn't hold
* {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
- * @throws UnsupportedOperationException if called on a non-automotive device.
* @hide
*/
@SystemApi
@@ -586,17 +640,90 @@ public class EthernetManager {
android.Manifest.permission.NETWORK_STACK,
android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
- public void disconnectNetwork(
+ public void disableInterface(
@NonNull String iface,
@Nullable @CallbackExecutor Executor executor,
- @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
Objects.requireNonNull(iface, "iface must be non-null");
- final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
- executor, listener);
+ final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+ executor, callback);
try {
mService.disconnectNetwork(iface, proxy);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Change ethernet setting.
+ *
+ * @param enabled enable or disable ethernet settings.
+ *
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void setEthernetEnabled(boolean enabled) {
+ try {
+ mService.setEthernetEnabled(enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Listen to changes in the state of ethernet.
+ *
+ * @param executor to run callbacks on.
+ * @param listener to listen ethernet state changed.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void addEthernetStateListener(@NonNull Executor executor,
+ @NonNull IntConsumer listener) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(listener);
+ synchronized (mListenerLock) {
+ maybeAddServiceListener();
+ mEthernetStateListeners.add(new ListenerInfo<IntConsumer>(executor, listener));
+ }
+ }
+
+ /**
+ * Removes a listener.
+ *
+ * @param listener to listen ethernet state changed.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void removeEthernetStateListener(@NonNull IntConsumer listener) {
+ Objects.requireNonNull(listener);
+ synchronized (mListenerLock) {
+ mEthernetStateListeners.removeIf(l -> l.listener == listener);
+ maybeRemoveServiceListener();
+ }
+ }
+
+ /**
+ * Returns an array of existing Ethernet interface names regardless whether the interface
+ * is available or not currently.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @SystemApi(client = MODULE_LIBRARIES)
+ @NonNull
+ public List<String> getInterfaceList() {
+ try {
+ return mService.getInterfaceList();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
index 544d02ba76ff..42e4c1ac55aa 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
@@ -18,10 +18,13 @@ package android.net;
import android.net.IpConfiguration;
import android.net.IEthernetServiceListener;
-import android.net.IEthernetNetworkManagementListener;
+import android.net.EthernetNetworkManagementException;
import android.net.EthernetNetworkUpdateRequest;
+import android.net.INetworkInterfaceOutcomeReceiver;
import android.net.ITetheredInterfaceCallback;
+import java.util.List;
+
/**
* Interface that answers queries about, and allows changing
* ethernet configuration.
@@ -39,7 +42,9 @@ interface IEthernetManager
void requestTetheredInterface(in ITetheredInterfaceCallback callback);
void releaseTetheredInterface(in ITetheredInterfaceCallback callback);
void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request,
- in IEthernetNetworkManagementListener listener);
- void connectNetwork(String iface, in IEthernetNetworkManagementListener listener);
- void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener);
+ in INetworkInterfaceOutcomeReceiver listener);
+ void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener);
+ void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener);
+ void setEthernetEnabled(boolean enabled);
+ List<String> getInterfaceList();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
index 6d2ba03f78d4..751605bb3849 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
@@ -21,6 +21,7 @@ import android.net.IpConfiguration;
/** @hide */
oneway interface IEthernetServiceListener
{
+ void onEthernetStateChanged(int state);
void onInterfaceStateChanged(String iface, int state, int role,
in IpConfiguration configuration);
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl
index 93edccfdafd9..85795ead7aea 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl
@@ -17,9 +17,9 @@
package android.net;
import android.net.EthernetNetworkManagementException;
-import android.net.Network;
/** @hide */
-oneway interface IEthernetNetworkManagementListener {
- void onComplete(in Network network, in EthernetNetworkManagementException exception);
+oneway interface INetworkInterfaceOutcomeReceiver {
+ void onResult(in String iface);
+ void onError(in EthernetNetworkManagementException e);
} \ No newline at end of file
diff --git a/packages/SettingsLib/SearchWidget/res/values-or/strings.xml b/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
index cf824deecd79..322571adc89c 100644
--- a/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"ସେଟିଂସ୍ ସନ୍ଧାନ କରନ୍ତୁ"</string>
+ <string name="search_menu" msgid="1914043873178389845">"ସେଟିଂସ ସନ୍ଧାନ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 74394283a54a..31036ec152d9 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1038,23 +1038,6 @@
<!-- Developer settings: text for the WebView provider selection toast shown if an invalid provider was chosen (i.e. the setting list was stale). [CHAR LIMIT=NONE] -->
<string name="select_webview_provider_toast_text">This choice is no longer valid. Try again.</string>
- <!-- Developer settings screen, convert userdata to file encryption option name -->
- <string name="convert_to_file_encryption">Convert to file encryption</string>
- <!-- Developer settings screen, convert userdata to file encryption summary when option is available -->
- <string name="convert_to_file_encryption_enabled">Convert\u2026</string>
- <!-- Developer settings screen, convert userdata to file encryption summary when option is already done -->
- <string name="convert_to_file_encryption_done">Already file encrypted</string>
- <!-- Title used on dialog with final prompt for converting to file encryption -->
- <string name="title_convert_fbe">Converting to file based encryption</string>
- <!-- Warning displayed on dialog with final prompt for converting to file encryption -->
- <string name="convert_to_fbe_warning">
- Convert data partition to file based encryption.\n
- !!Warning!! This will erase all your data.\n
- This feature is alpha, and may not work correctly.\n
- Press \'Wipe and convert\u2026\' to continue.</string>
- <!-- Button on dialog that triggers convertion to file encryption -->
- <string name="button_convert_fbe">Wipe and convert\u2026</string>
-
<!-- Name of feature to change color setting for the display [CHAR LIMIT=60] -->
<string name="picture_color_mode">Picture color mode</string>
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/SettingsProvider/res/values-or/strings.xml b/packages/SettingsProvider/res/values-or/strings.xml
index 486d8ffaa500..85add41b1ee1 100644
--- a/packages/SettingsProvider/res/values-or/strings.xml
+++ b/packages/SettingsProvider/res/values-or/strings.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4567566098528588863">"ସେଟିଙ୍ଗ ଷ୍ଟୋରେଜ୍‌"</string>
+ <string name="app_label" msgid="4567566098528588863">"ସେଟିଂସ ଷ୍ଟୋରେଜ୍‌"</string>
<string name="wifi_softap_config_change" msgid="5688373762357941645">"ହଟସ୍ପଟ୍ ସେଟିଂସ୍ ବଦଳାଯାଇଛି"</string>
<string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"ବିବରଣୀ ଦେଖିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
</resources>
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/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/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
index 61071235db0b..8147877a8a29 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
@@ -150,24 +150,27 @@ class PrivacyDialogController(
packageName: String,
userId: Int,
permGroupName: CharSequence,
- attributionTag: CharSequence?
+ attributionTag: CharSequence?,
+ isAttributionSupported: Boolean
): Intent
{
lateinit var intent: Intent
- if (attributionTag != null) {
+ if (attributionTag != null && isAttributionSupported) {
intent = Intent(Intent.ACTION_MANAGE_PERMISSION_USAGE)
intent.setPackage(packageName)
intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permGroupName.toString())
intent.putExtra(Intent.EXTRA_ATTRIBUTION_TAGS, arrayOf(attributionTag.toString()))
intent.putExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, true)
val resolveInfo = packageManager.resolveActivity(
- intent, PackageManager.ResolveInfoFlags.of(0))
- ?: return getDefaultManageAppPermissionsIntent(packageName, userId)
- intent.component = ComponentName(packageName, resolveInfo.activityInfo.name)
- return intent
- } else {
- return getDefaultManageAppPermissionsIntent(packageName, userId)
+ intent, PackageManager.ResolveInfoFlags.of(0))
+ if (resolveInfo != null && resolveInfo.activityInfo != null &&
+ resolveInfo.activityInfo.permission ==
+ android.Manifest.permission.START_VIEW_PERMISSION_USAGE) {
+ intent.component = ComponentName(packageName, resolveInfo.activityInfo.name)
+ return intent
+ }
}
+ return getDefaultManageAppPermissionsIntent(packageName, userId)
}
fun getDefaultManageAppPermissionsIntent(packageName: String, userId: Int): Intent {
@@ -226,9 +229,15 @@ class PrivacyDialogController(
userInfo?.isManagedProfile ?: false,
it.isPhoneCall,
it.permissionGroupName,
- getManagePermissionIntent(it.packageName, userId,
- it.permissionGroupName,
- it.attributionTag)
+ getManagePermissionIntent(
+ it.packageName,
+ userId,
+ it.permissionGroupName,
+ it.attributionTag,
+ // attributionLabel is set only when subattribution policies
+ // are supported and satisfied
+ it.attributionLabel != null
+ )
)
}
} else {
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/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/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
index 350822691121..38b448fb362c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
@@ -19,8 +19,11 @@ package com.android.systemui.privacy
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
+import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
+import android.content.pm.PackageManager.ResolveInfoFlags
+import android.content.pm.ResolveInfo
import android.content.pm.UserInfo
import android.os.Process.SYSTEM_UID
import android.os.UserHandle
@@ -648,6 +651,77 @@ class PrivacyDialogControllerTest : SysuiTestCase() {
}
}
+ @Test
+ fun testCorrectIntentSubAttribution() {
+ val usage = createMockPermGroupUsage(
+ attributionTag = TEST_ATTRIBUTION_TAG,
+ attributionLabel = "TEST_LABEL"
+ )
+
+ val activityInfo = createMockActivityInfo()
+ val resolveInfo = createMockResolveInfo(activityInfo)
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+ .thenAnswer { resolveInfo }
+ controller.showDialog(context)
+ exhaustExecutors()
+
+ dialogProvider.list?.let { list ->
+ val navigationIntent = list.get(0).navigationIntent!!
+ assertThat(navigationIntent.action).isEqualTo(Intent.ACTION_MANAGE_PERMISSION_USAGE)
+ assertThat(navigationIntent.getStringExtra(Intent.EXTRA_PERMISSION_GROUP_NAME))
+ .isEqualTo(PERM_CAMERA)
+ assertThat(navigationIntent.getStringArrayExtra(Intent.EXTRA_ATTRIBUTION_TAGS))
+ .isEqualTo(arrayOf(TEST_ATTRIBUTION_TAG.toString()))
+ assertThat(navigationIntent.getBooleanExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, false))
+ .isTrue()
+ }
+ }
+
+ @Test
+ fun testDefaultIntentOnMissingAttributionLabel() {
+ val usage = createMockPermGroupUsage(
+ attributionTag = TEST_ATTRIBUTION_TAG
+ )
+
+ val activityInfo = createMockActivityInfo()
+ val resolveInfo = createMockResolveInfo(activityInfo)
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+ .thenAnswer { resolveInfo }
+ controller.showDialog(context)
+ exhaustExecutors()
+
+ dialogProvider.list?.let { list ->
+ assertThat(isIntentEqual(list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
+ .isTrue()
+ }
+ }
+
+ @Test
+ fun testDefaultIntentOnIncorrectPermission() {
+ val usage = createMockPermGroupUsage(
+ attributionTag = TEST_ATTRIBUTION_TAG
+ )
+
+ val activityInfo = createMockActivityInfo(
+ permission = "INCORRECT_PERMISSION"
+ )
+ val resolveInfo = createMockResolveInfo(activityInfo)
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+ .thenAnswer { resolveInfo }
+ controller.showDialog(context)
+ exhaustExecutors()
+
+ dialogProvider.list?.let { list ->
+ assertThat(isIntentEqual(list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
+ .isTrue()
+ }
+ }
+
private fun exhaustExecutors() {
FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
}
@@ -680,6 +754,24 @@ class PrivacyDialogControllerTest : SysuiTestCase() {
return user * UserHandle.PER_USER_RANGE + nextUid++
}
+ private fun createMockResolveInfo(
+ activityInfo: ActivityInfo? = null
+ ): ResolveInfo {
+ val resolveInfo = mock(ResolveInfo::class.java)
+ resolveInfo.activityInfo = activityInfo
+ return resolveInfo
+ }
+
+ private fun createMockActivityInfo(
+ permission: String = android.Manifest.permission.START_VIEW_PERMISSION_USAGE,
+ className: String = "TEST_CLASS_NAME"
+ ): ActivityInfo {
+ val activityInfo = mock(ActivityInfo::class.java)
+ activityInfo.permission = permission
+ activityInfo.name = className
+ return activityInfo
+ }
+
private fun createMockPermGroupUsage(
packageName: String = TEST_PACKAGE_NAME,
uid: Int = generateUidForUser(USER_ID),
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/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 3f712dd1492f..3801c2473c11 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -2260,10 +2260,12 @@ message MetricsEvent {
ACCOUNTS_WORK_PROFILE_SETTINGS = 401;
// Settings -> Dev options -> Convert to file encryption
- CONVERT_FBE = 402;
+ // DEPRECATED: this setting was removed in Android T.
+ CONVERT_FBE = 402 [deprecated=true];
// Settings -> Dev options -> Convert to file encryption -> WIPE AND CONVERT...
- CONVERT_FBE_CONFIRM = 403;
+ // DEPRECATED: this setting was removed in Android T.
+ CONVERT_FBE_CONFIRM = 403 [deprecated=true];
// Settings -> Dev options -> Running services
RUNNING_SERVICES = 404;
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/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 186ff6215c9c..2015dc929a59 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -196,13 +196,15 @@ public class NetworkTimeUpdateService extends Binder {
* Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
* test value, i.e. so the normal value will be used next time.
*/
- void setServerConfigForTests(@Nullable String hostname, @Nullable Duration timeout) {
+ void setServerConfigForTests(
+ @Nullable String hostname, @Nullable Integer port, @Nullable Duration timeout) {
mContext.enforceCallingPermission(
android.Manifest.permission.SET_TIME, "set NTP server config for tests");
mLocalLog.log("Setting server config for tests: hostname=" + hostname
+ + ", port=" + port
+ ", timeout=" + timeout);
- mTime.setServerConfigForTests(hostname, timeout);
+ mTime.setServerConfigForTests(hostname, port, timeout);
}
private void onPollNetworkTime(int event) {
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
index 464af01a009a..d7504ceb9d4d 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
@@ -46,6 +46,7 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
*/
private static final String SHELL_COMMAND_SET_SERVER_CONFIG = "set_server_config";
private static final String SET_SERVER_CONFIG_HOSTNAME_ARG = "--hostname";
+ private static final String SET_SERVER_CONFIG_PORT_ARG = "--port";
private static final String SET_SERVER_CONFIG_TIMEOUT_ARG = "--timeout_millis";
@NonNull
@@ -87,6 +88,7 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
private int runSetServerConfig() {
String hostname = null;
+ Integer port = null;
Duration timeout = null;
String opt;
while ((opt = getNextArg()) != null) {
@@ -95,6 +97,10 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
hostname = getNextArgRequired();
break;
}
+ case SET_SERVER_CONFIG_PORT_ARG: {
+ port = Integer.parseInt(getNextArgRequired());
+ break;
+ }
case SET_SERVER_CONFIG_TIMEOUT_ARG: {
timeout = Duration.ofMillis(Integer.parseInt(getNextArgRequired()));
break;
@@ -104,7 +110,7 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
}
}
}
- mNetworkTimeUpdateService.setServerConfigForTests(hostname, timeout);
+ mNetworkTimeUpdateService.setServerConfigForTests(hostname, port, timeout);
return 0;
}
@@ -120,8 +126,9 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
pw.printf(" Refreshes the latest time. Prints whether it was successful.\n");
pw.printf(" %s\n", SHELL_COMMAND_SET_SERVER_CONFIG);
pw.printf(" Sets the NTP server config for tests. The config is not persisted.\n");
- pw.printf(" Options: [%s <hostname>] [%s <millis>]\n",
- SET_SERVER_CONFIG_HOSTNAME_ARG, SET_SERVER_CONFIG_TIMEOUT_ARG);
+ pw.printf(" Options: [%s <hostname>] [%s <port>] [%s <millis>]\n",
+ SET_SERVER_CONFIG_HOSTNAME_ARG, SET_SERVER_CONFIG_PORT_ARG,
+ SET_SERVER_CONFIG_TIMEOUT_ARG);
pw.printf(" Each key/value is optional and must be specified to override the\n");
pw.printf(" normal value, not specifying a key causes it to reset to the original.\n");
pw.println();
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 677fc7931f64..a2cfe4928249 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3130,23 +3130,6 @@ class StorageManagerService extends IStorageManager.Stub
}
/**
- * Is userdata convertible to file based encryption?
- * @return non zero for convertible
- */
- @Override
- public boolean isConvertibleToFBE() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- try {
- return mVold.isConvertibleToFbe();
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return false;
- }
- }
-
- /**
* Check whether the device supports filesystem checkpointing.
*
* @return true if the device supports filesystem checkpointing, false otherwise.
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/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 7ed3dcf40f65..9626bbe0b4b2 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -407,7 +407,6 @@ public class OomAdjuster {
uids.clear();
uids.put(uidRec.getUid(), uidRec);
updateUidsLSP(uids, SystemClock.elapsedRealtime());
- mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(uids);
}
}
@@ -1144,8 +1143,6 @@ public class OomAdjuster {
}
}
- mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(activeUids);
-
return mService.mAppProfiler.updateLowMemStateLSP(numCached, numEmpty, numTrimming);
}
@@ -1180,6 +1177,11 @@ public class OomAdjuster {
@GuardedBy({"mService", "mProcLock"})
private void updateUidsLSP(ActiveUids activeUids, final long nowElapsed) {
+ // This compares previously set procstate to the current procstate in regards to whether
+ // or not the app's network access will be blocked. So, this needs to be called before
+ // we update the UidRecord's procstate by calling {@link UidRecord#setSetProcState}.
+ mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(activeUids);
+
ArrayList<UidRecord> becameIdle = mTmpBecameIdle;
becameIdle.clear();
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/locales/TEST_MAPPING b/services/core/java/com/android/server/locales/TEST_MAPPING
index 27d2851a1bbe..160542b6aa0f 100644
--- a/services/core/java/com/android/server/locales/TEST_MAPPING
+++ b/services/core/java/com/android/server/locales/TEST_MAPPING
@@ -9,10 +9,13 @@
]
},
{
- "name": "CtsLocaleManagerTestCases"
- },
- {
"name": "CtsLocaleManagerHostTestCases"
}
+ ],
+ "postsubmit": [
+ // TODO(b/225192026): Move back to presubmit after b/225192026 is fixed
+ {
+ "name": "CtsLocaleManagerTestCases"
+ }
]
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 5902f487d353..45c5116bea59 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -89,6 +89,14 @@ public class Installer extends SystemService {
*/
public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3;
+ /**
+ * The results of {@code getOdexVisibility}. See
+ * {@link #getOdexVisibility(String, String, String)} for details.
+ */
+ public static final int ODEX_NOT_FOUND = 0;
+ public static final int ODEX_IS_PUBLIC = 1;
+ public static final int ODEX_IS_PRIVATE = 2;
+
public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
@@ -866,6 +874,15 @@ public class Installer extends SystemService {
}
}
+ /**
+ * Prepares the app profile for the package at the given path:
+ * <ul>
+ * <li>Creates the current profile for the given user ID, unless the user ID is
+ * {@code UserHandle.USER_NULL}.</li>
+ * <li>Merges the profile from the dex metadata file (if present) into the reference
+ * profile.</li>
+ * </ul>
+ */
public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId,
String profileName, String codePath, String dexMetadataPath) throws InstallerException {
if (!checkBeforeRemote()) return false;
@@ -1016,6 +1033,33 @@ public class Installer extends SystemService {
}
}
+ /**
+ * Returns the visibility of the optimized artifacts.
+ *
+ * @param packageName name of the package.
+ * @param apkPath path to the APK.
+ * @param instructionSet instruction set of the optimized artifacts.
+ * @param outputPath path to the directory that contains the optimized artifacts (i.e., the
+ * directory that {@link #dexopt} outputs to).
+ *
+ * @return {@link #ODEX_NOT_FOUND} if the optimized artifacts are not found, or
+ * {@link #ODEX_IS_PUBLIC} if the optimized artifacts are accessible by all apps, or
+ * {@link #ODEX_IS_PRIVATE} if the optimized artifacts are only accessible by this app.
+ *
+ * @throws InstallerException if failed to get the visibility of the optimized artifacts.
+ */
+ public int getOdexVisibility(String packageName, String apkPath, String instructionSet,
+ String outputPath) throws InstallerException {
+ if (!checkBeforeRemote()) return -1;
+ BlockGuard.getVmPolicy().onPathAccess(apkPath);
+ BlockGuard.getVmPolicy().onPathAccess(outputPath);
+ try {
+ return mInstalld.getOdexVisibility(packageName, apkPath, instructionSet, outputPath);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
public static class InstallerException extends Exception {
public InstallerException(String detailMessage) {
super(detailMessage);
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 69d498794e64..27c6d9bec2e8 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -319,28 +319,42 @@ public class PackageDexOptimizer {
String profileName = ArtManager.getProfileName(
i == 0 ? null : pkg.getSplitNames()[i - 1]);
+ final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
+ || packageUseInfo.isUsedByOtherApps(path);
+ String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter());
+ // If the app is used by other apps, we must not use the existing profile because it
+ // may contain user data, unless the profile is newly created on install.
+ final boolean resetProfile = isProfileGuidedCompilerFilter(compilerFilter)
+ && isUsedByOtherApps
+ && options.getCompilationReason() != PackageManagerService.REASON_INSTALL;
String dexMetadataPath = null;
- if (options.isDexoptInstallWithDexMetadata()) {
+ if (options.isDexoptInstallWithDexMetadata() || resetProfile) {
File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path));
dexMetadataPath = dexMetadataFile == null
? null : dexMetadataFile.getAbsolutePath();
}
- final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
- || packageUseInfo.isUsedByOtherApps(path);
- final String compilerFilter = getRealCompilerFilter(pkg,
- options.getCompilerFilter(), isUsedByOtherApps);
// If we don't have to check for profiles updates assume
// PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA which will be a no-op with respect to
// profiles.
- final int profileAnalysisResult = options.isCheckForProfileUpdates()
- ? analyseProfiles(pkg, sharedGid, profileName, compilerFilter)
- : PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
+ int profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
+ if (resetProfile) {
+ if (!resetProfile(pkg, profileName, path, dexMetadataPath)) {
+ // Fall back to use the shared filter.
+ compilerFilter =
+ PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+ PackageManagerService.REASON_SHARED);
+ }
+ } else if (options.isCheckForProfileUpdates()) {
+ profileAnalysisResult =
+ analyseProfiles(pkg, sharedGid, profileName, compilerFilter);
+ }
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
// flags.
- final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, options);
+ final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, resetProfile,
+ options);
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter,
@@ -391,6 +405,30 @@ public class PackageDexOptimizer {
}
/**
+ * Resets the profiles of the dex file at {@code path} belonging to the package {@code pkg} to
+ * the initial state as if the package is newly installed. Returns true on success, or false
+ * otherwise.
+ */
+ @GuardedBy("mInstallLock")
+ private boolean resetProfile(AndroidPackage pkg, String profileName, String path,
+ @Nullable String dexMetadataPath) {
+ if (dexMetadataPath != null) {
+ try {
+ mInstaller.clearAppProfiles(pkg.getPackageName(), profileName);
+ final int appId = UserHandle.getAppId(pkg.getUid());
+ mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL,
+ appId, profileName, path, dexMetadataPath);
+ return true;
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to reset profile", e);
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
* Performs dexopt on the {@code path} belonging to the package {@code pkg}.
*
* @return
@@ -405,15 +443,15 @@ public class PackageDexOptimizer {
String classLoaderContext, int dexoptFlags, int uid,
CompilerStats.PackageStats packageStats, boolean downgrade, String profileName,
String dexMetadataPath, int compilationReason) {
- int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
- profileAnalysisResult, downgrade);
+ String oatDir = getPackageOatDirIfSupported(pkg,
+ pkgSetting.getTransientState().isUpdatedSystemApp());
+
+ int dexoptNeeded = getDexoptNeeded(pkg.getPackageName(), path, isa, compilerFilter,
+ classLoaderContext, profileAnalysisResult, downgrade, dexoptFlags, oatDir);
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
return DEX_OPT_SKIPPED;
}
- String oatDir = getPackageOatDirIfSupported(pkg,
- pkgSetting.getTransientState().isUpdatedSystemApp());
-
Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
+ " pkg=" + pkg.getPackageName() + " isa=" + isa
+ " dexoptFlags=" + printDexoptFlags(dexoptFlags)
@@ -456,6 +494,7 @@ public class PackageDexOptimizer {
/**
* Perform dexopt (if needed) on a system server code path).
*/
+ @GuardedBy("mInstallLock")
@DexOptResult
public int dexoptSystemServerPath(
String dexPath, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) {
@@ -466,12 +505,15 @@ public class PackageDexOptimizer {
int result = DEX_OPT_SKIPPED;
for (String isa : dexUseInfo.getLoaderIsas()) {
int dexoptNeeded = getDexoptNeeded(
+ PackageManagerService.PLATFORM_PACKAGE_NAME,
dexPath,
isa,
options.getCompilerFilter(),
dexUseInfo.getClassLoaderContext(),
PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES,
- /* downgrade= */ false);
+ /* downgrade= */ false,
+ dexoptFlags,
+ /* oatDir= */ null);
if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
continue;
@@ -714,7 +756,7 @@ public class PackageDexOptimizer {
}
/**
- * Returns the compiler filter that should be used to optimize the package code.
+ * Returns the compiler filter that should be used to optimize the secondary dex.
* The target filter will be updated if the package code is used by other apps
* or if it has the safe mode flag set.
*/
@@ -754,12 +796,12 @@ public class PackageDexOptimizer {
}
/**
- * Returns the compiler filter that should be used to optimize the package code.
- * The target filter will be updated if the package code is used by other apps
- * or if it has the safe mode flag set.
+ * Returns the compiler filter that should be used to optimize the primary dex.
+ * The target filter will be updated if the package has the safe mode flag set. Note that this
+ * method does NOT take other app use into account. The caller should be responsible for
+ * handling the case where the package code is used by other apps.
*/
- private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter,
- boolean isUsedByOtherApps) {
+ private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter) {
// When an app or priv app is configured to run out of box, only verify it.
if (pkg.isUseEmbeddedDex()
|| (pkg.isPrivileged()
@@ -783,12 +825,6 @@ public class PackageDexOptimizer {
return getSafeModeCompilerFilter(targetCompilerFilter);
}
- if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
- // If the dex files is used by other apps, apply the shared filter.
- return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_SHARED);
- }
-
return targetCompilerFilter;
}
@@ -799,14 +835,16 @@ public class PackageDexOptimizer {
private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0,
info.getHiddenApiEnforcementPolicy(), info.splitDependencies,
- info.requestsIsolatedSplitLoading(), compilerFilter, options);
+ info.requestsIsolatedSplitLoading(), compilerFilter, false /* resetProfile */,
+ options);
}
+
private int getDexFlags(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting,
- String compilerFilter, DexoptOptions options) {
+ String compilerFilter, boolean resetProfile, DexoptOptions options) {
return getDexFlags(pkg.isDebuggable(),
AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting),
pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter,
- options);
+ resetProfile, options);
}
/**
@@ -815,13 +853,15 @@ public class PackageDexOptimizer {
*/
private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy,
SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
- String compilerFilter, DexoptOptions options) {
+ String compilerFilter, boolean resetProfile, DexoptOptions options) {
// Profile guide compiled oat files should not be public unles they are based
// on profiles from dex metadata archives.
// The flag isDexoptInstallWithDexMetadata applies only on installs when we know that
// the user does not have an existing profile.
+ // The flag resetProfile applies only when the existing profile is already reset.
boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
- boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata();
+ boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata()
+ || resetProfile;
int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
// Some apps are executed with restrictions on hidden API usage. If this app is one
// of them, pass a flag to dexopt to enable the same restrictions during compilation.
@@ -866,8 +906,19 @@ public class PackageDexOptimizer {
* Assesses if there's a need to perform dexopt on {@code path} for the given
* configuration (isa, compiler filter, profile).
*/
- private int getDexoptNeeded(String path, String isa, String compilerFilter,
- String classLoaderContext, int profileAnalysisResult, boolean downgrade) {
+ @GuardedBy("mInstallLock")
+ private int getDexoptNeeded(String packageName, String path, String isa, String compilerFilter,
+ String classLoaderContext, int profileAnalysisResult, boolean downgrade,
+ int dexoptFlags, String oatDir) {
+ final boolean shouldBePublic = (dexoptFlags & DEXOPT_PUBLIC) != 0;
+ // If the artifacts should be public while the current artifacts are not, we should
+ // re-compile anyway.
+ if (shouldBePublic && isOdexPrivate(packageName, path, isa, oatDir)) {
+ // Ensure compilation by pretending a compiler filter change on the apk/odex location
+ // (the reason for the '-'. A positive value means the 'oat' location).
+ return adjustDexoptNeeded(-DexFile.DEX2OAT_FOR_FILTER);
+ }
+
int dexoptNeeded;
try {
// A profile guided optimizations with an empty profile is essentially 'verify' and
@@ -901,6 +952,18 @@ public class PackageDexOptimizer {
return compilerFilter.endsWith("-profile");
}
+ /** Returns true if the current artifacts of the app are private to the app itself. */
+ @GuardedBy("mInstallLock")
+ private boolean isOdexPrivate(String packageName, String path, String isa, String oatDir) {
+ try {
+ return mInstaller.getOdexVisibility(packageName, path, isa, oatDir)
+ == Installer.ODEX_IS_PRIVATE;
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to get odex visibility for " + path, e);
+ return false;
+ }
+ }
+
/**
* Checks if there is an update on the profile information of the {@code pkg}.
* If the compiler filter is not profile guided the method returns a safe default:
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/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 9c74dd795d30..88a298a756d4 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -52,6 +52,9 @@
"options": [
{
"include-filter": "com.google.android.security.gts.PackageVerifierTest"
+ },
+ {
+ "exclude-filter": "com.google.android.security.gts.PackageVerifierTest#testAdbInstall_timeout_allowed"
}
]
},
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/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 20cd8f5c12f8..adca21676f9d 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -198,6 +198,8 @@ public class TrustAgentWrapper {
// Fall through.
case MSG_REVOKE_TRUST:
mTrusted = false;
+ mTrustable = false;
+ mWaitingForTrustableDowngrade = false;
mDisplayTrustGrantedMessage = false;
mMessage = null;
mHandler.removeMessages(MSG_TRUST_TIMEOUT);
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 6adf733ddae9..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);
@@ -1360,6 +1324,32 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
+ public void sendSigningResult(
+ IBinder sessionToken, String signingId, byte[] result, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "sendSigningResult(signingId=%s)", signingId);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "sendSigningResult");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).sendSigningResult(signingId, result);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in sendSigningResult", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void setSurface(IBinder sessionToken, Surface surface, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -1679,7 +1669,6 @@ public class TvInteractiveAppManagerService extends SystemService {
}
boolean shouldBind = (!serviceState.mSessionTokens.isEmpty())
- || (serviceState.mPendingPrepare)
|| (!serviceState.mPendingAppLinkInfo.isEmpty())
|| (!serviceState.mPendingAppLinkCommand.isEmpty());
@@ -1831,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;
}
@@ -1894,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();
@@ -2221,6 +2188,24 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
+ public void onRequestSigning(String id, String algorithm, String alias, byte[] data) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onRequestSigning");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onRequestSigning(
+ id, algorithm, alias, data, mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onRequestSigning", e);
+ }
+ }
+ }
+
+ @Override
public void onAdRequest(AdRequest request) {
synchronized (mLock) {
if (DEBUG) {
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 ba00beea47cc..edfd6ed5f63d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -15,6 +15,7 @@
*/
package com.android.server.devicepolicy;
+import android.accounts.Account;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyDrawableResource;
@@ -138,6 +139,11 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
return null;
}
+ public void finalizeWorkProfileProvisioning(
+ UserHandle managedProfileUser, Account migratedAccount) {
+
+ }
+
public void provisionFullyManagedDevice(
FullyManagedDeviceProvisioningParams provisioningParams, String callerPackage) {
}
@@ -171,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(
@@ -183,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 850fdee0c733..e6b57e052293 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -27,6 +27,7 @@ import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDG
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
+import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
@@ -45,6 +46,7 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_IDS;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE_DRAWABLE;
@@ -2122,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);
@@ -14772,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;
}
@@ -14804,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)) {
@@ -14819,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.
@@ -14836,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) {
@@ -17781,7 +17789,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (provisioningParams.isOrganizationOwnedProvisioning()) {
synchronized (getLockObject()) {
- markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id);
+ setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id,
+ true);
}
}
@@ -17808,6 +17817,35 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ @Override
+ public void finalizeWorkProfileProvisioning(UserHandle managedProfileUser,
+ Account migratedAccount) {
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+ if (!isManagedProfile(managedProfileUser.getIdentifier())) {
+ throw new IllegalStateException("Given user is not a managed profile");
+ }
+ ComponentName profileOwnerComponent =
+ mOwners.getProfileOwnerComponent(managedProfileUser.getIdentifier());
+ if (profileOwnerComponent == null) {
+ throw new IllegalStateException("There is no profile owner on the given profile");
+ }
+ Intent primaryProfileSuccessIntent = new Intent(ACTION_MANAGED_PROFILE_PROVISIONED);
+ primaryProfileSuccessIntent.setPackage(profileOwnerComponent.getPackageName());
+ primaryProfileSuccessIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ primaryProfileSuccessIntent.putExtra(Intent.EXTRA_USER, managedProfileUser);
+
+ if (migratedAccount != null) {
+ primaryProfileSuccessIntent.putExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE,
+ migratedAccount);
+ }
+
+ mContext.sendBroadcastAsUser(primaryProfileSuccessIntent,
+ UserHandle.of(getProfileParentId(managedProfileUser.getIdentifier())));
+ }
+
/**
* Callback called at the beginning of {@link #createAndProvisionManagedProfile(
* ManagedProfileProvisioningParams, String)} after the relevant prechecks have passed.
@@ -18682,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));
@@ -18709,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);
}
@@ -18723,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));
@@ -18745,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);
}
diff --git a/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
index 35f1e585931b..644d450a7a88 100644
--- a/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
+++ b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
@@ -24,6 +24,8 @@ import android.net.SntpClient;
import android.os.Environment;
import android.util.Log;
+import libcore.io.Streams;
+
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -37,8 +39,6 @@ import java.net.InetAddress;
import java.net.URL;
import java.util.Random;
-import libcore.io.Streams;
-
/*
* Test Service that tries to connect to the web via different methods and outputs the results to
* the log and a output file.
@@ -146,7 +146,7 @@ public class BandwidthEnforcementTestService extends IntentService {
final ConnectivityManager mCM = context.getSystemService(ConnectivityManager.class);
final Network network = mCM.getActiveNetwork();
- if (client.requestTime("0.pool.ntp.org", 10000, network)) {
+ if (client.requestTime("0.pool.ntp.org", SntpClient.STANDARD_NTP_PORT, 10000, network)) {
return true;
}
return false;
diff --git a/tests/TrustTests/AndroidManifest.xml b/tests/TrustTests/AndroidManifest.xml
index 68bc1f69628f..8b4cbfd0e44b 100644
--- a/tests/TrustTests/AndroidManifest.xml
+++ b/tests/TrustTests/AndroidManifest.xml
@@ -68,6 +68,16 @@
<action android:name="android.service.trust.TrustAgentService" />
</intent-filter>
</service>
+
+ <service
+ android:name=".TemporaryAndRenewableTrustAgent"
+ android:exported="true"
+ android:label="Test Agent"
+ android:permission="android.permission.BIND_TRUST_AGENT">
+ <intent-filter>
+ <action android:name="android.service.trust.TrustAgentService" />
+ </intent-filter>
+ </service>
</application>
<!-- self-instrumenting test package. -->
diff --git a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
index 790afd389152..af7a98c22ad1 100644
--- a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
+++ b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
@@ -60,7 +60,6 @@ class GrantAndRevokeTrustTest {
@Test
fun sleepingDeviceWithoutGrantLocksDevice() {
uiDevice.sleep()
- await()
lockStateTrackingRule.assertLocked()
}
@@ -69,7 +68,6 @@ class GrantAndRevokeTrustTest {
fun grantKeepsDeviceUnlocked() {
trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0)
uiDevice.sleep()
- await()
lockStateTrackingRule.assertUnlocked()
}
@@ -80,7 +78,6 @@ class GrantAndRevokeTrustTest {
await()
uiDevice.sleep()
trustAgentRule.agent.revokeTrust()
- await()
lockStateTrackingRule.assertLocked()
}
diff --git a/tests/TrustTests/src/android/trust/test/LockUserTest.kt b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
index 8f200a64450e..a7dd41ad2e98 100644
--- a/tests/TrustTests/src/android/trust/test/LockUserTest.kt
+++ b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
@@ -24,7 +24,6 @@ import android.trust.test.lib.TrustAgentRule
import android.util.Log
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
@@ -52,9 +51,8 @@ class LockUserTest {
fun lockUser_locksTheDevice() {
Log.i(TAG, "Locking user")
trustAgentRule.agent.lockUser()
- await()
- assertThat(lockStateTrackingRule.lockState.locked).isTrue()
+ lockStateTrackingRule.assertLocked()
}
companion object {
diff --git a/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
new file mode 100644
index 000000000000..14c227b1f678
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.trust.test
+
+import android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE
+import android.trust.BaseTrustAgentService
+import android.trust.TrustTestActivity
+import android.trust.test.lib.LockStateTrackingRule
+import android.trust.test.lib.ScreenLockRule
+import android.trust.test.lib.TrustAgentRule
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import androidx.test.uiautomator.UiDevice
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.runner.RunWith
+
+/**
+ * Test for testing revokeTrust & grantTrust for renewable trust.
+ *
+ * atest TrustTests:TemporaryAndRenewableTrustTest
+ */
+@RunWith(AndroidJUnit4::class)
+class TemporaryAndRenewableTrustTest {
+ private val uiDevice = UiDevice.getInstance(getInstrumentation())
+ private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java)
+ private val lockStateTrackingRule = LockStateTrackingRule()
+ private val trustAgentRule = TrustAgentRule<TemporaryAndRenewableTrustAgent>()
+
+ @get:Rule
+ val rule: RuleChain = RuleChain
+ .outerRule(activityScenarioRule)
+ .around(ScreenLockRule())
+ .around(lockStateTrackingRule)
+ .around(trustAgentRule)
+
+ @Before
+ fun manageTrust() {
+ trustAgentRule.agent.setManagingTrust(true)
+ }
+
+ // This test serves a baseline for Grant tests, verifying that the default behavior of the
+ // device is to lock when put to sleep
+ @Test
+ fun sleepingDeviceWithoutGrantLocksDevice() {
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ @Test
+ fun grantTrustLockedDevice_deviceStaysLocked() {
+ uiDevice.sleep()
+ lockStateTrackingRule.assertLocked()
+
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+ uiDevice.wakeUp()
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ @Test
+ fun grantTrustUnlockedDevice_deviceLocksOnScreenOff() {
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ @Test
+ fun grantTrustLockedDevice_grantTrustOnLockedDeviceUnlocksDevice() {
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+ uiDevice.wakeUp()
+
+ lockStateTrackingRule.assertUnlocked()
+ }
+
+ @Test
+ fun grantTrustLockedDevice_revokeTrustPreventsSubsequentUnlock() {
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+
+ trustAgentRule.agent.revokeTrust()
+ await(500)
+ uiDevice.wakeUp()
+ await(500)
+
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ companion object {
+ private const val TAG = "TemporaryAndRenewableTrustTest"
+ private const val GRANT_MESSAGE = "granted by test"
+ private fun await(millis: Long) = Thread.sleep(millis)
+ }
+}
+
+class TemporaryAndRenewableTrustAgent : BaseTrustAgentService()
diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
index 0023af8893e2..834f2122a21b 100644
--- a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
@@ -52,8 +52,29 @@ class LockStateTrackingRule : TestRule {
}
}
- fun assertLocked() = assertThat(lockState.locked).isTrue()
- fun assertUnlocked() = assertThat(lockState.locked).isFalse()
+ fun assertLocked() {
+ val maxWaits = 50
+ var waitCount = 0
+
+ while ((lockState.locked == false) && waitCount < maxWaits) {
+ Log.i(TAG, "phone still locked, wait 50ms more ($waitCount)")
+ Thread.sleep(50)
+ waitCount++
+ }
+ assertThat(lockState.locked).isTrue()
+ }
+
+ fun assertUnlocked() {
+ val maxWaits = 50
+ var waitCount = 0
+
+ while ((lockState.locked == true) && waitCount < maxWaits) {
+ Log.i(TAG, "phone still unlocked, wait 50ms more ($waitCount)")
+ Thread.sleep(50)
+ waitCount++
+ }
+ assertThat(lockState.locked).isFalse()
+ }
inner class Listener : TrustListener {
override fun onTrustChanged(