summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rw-r--r--core/api/current.txt57
-rw-r--r--core/api/system-current.txt49
-rw-r--r--core/api/test-current.txt4
-rw-r--r--core/java/Android.bp8
-rw-r--r--core/java/android/app/ContextImpl.java12
-rw-r--r--core/java/android/app/ILocaleManager.aidl5
-rw-r--r--core/java/android/app/KeyguardManager.java14
-rw-r--r--core/java/android/app/LocaleManager.java28
-rw-r--r--core/java/android/app/TEST_MAPPING19
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java147
-rw-r--r--core/java/android/app/admin/FactoryResetProtectionPolicy.java15
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl7
-rw-r--r--core/java/android/app/usage/BroadcastResponseStats.java2
-rw-r--r--core/java/android/content/Context.java26
-rw-r--r--core/java/android/content/ContextWrapper.java4
-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/ShortcutInfo.java131
-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/IPermissionController.aidl2
-rw-r--r--core/java/android/permission/IPermissionManager.aidl2
-rw-r--r--core/java/android/permission/PermissionControllerManager.java6
-rw-r--r--core/java/android/permission/PermissionControllerService.java19
-rw-r--r--core/java/android/permission/PermissionManager.java14
-rw-r--r--core/java/android/permission/PermissionUsageHelper.java15
-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/util/TimingsTraceLog.java2
-rw-r--r--core/java/android/view/ContentRecordingSession.java38
-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/KernelAllocationStats.java26
-rw-r--r--core/java/com/android/server/SystemConfig.java4
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/com_android_internal_os_KernelAllocationStats.cpp149
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/tests/coretests/src/android/net/SntpClientTest.java3
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java2
-rw-r--r--core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java14
-rw-r--r--data/etc/services.core.protolog.json18
-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--libs/hwui/HardwareBitmapUploader.cpp12
-rw-r--r--libs/hwui/HardwareBitmapUploader.h2
-rw-r--r--libs/hwui/hwui/Bitmap.cpp4
-rw-r--r--location/java/android/location/GnssExcessPathInfo.java375
-rw-r--r--location/java/android/location/GnssReflectingPlane.java44
-rw-r--r--location/java/android/location/GnssSingleSatCorrection.java395
-rw-r--r--media/java/android/media/MediaActionSound.java5
-rw-r--r--media/java/android/media/MediaFormat.java5
-rw-r--r--media/java/android/media/Spatializer.java8
-rw-r--r--media/java/android/media/projection/IMediaProjection.aidl13
-rw-r--r--media/java/android/media/projection/MediaProjection.java57
-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/ITvInteractiveAppClient.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl1
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl1
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppManager.java81
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppService.java79
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppView.java99
-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/EthernetNetworkUpdateRequest.java28
-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/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml2
-rw-r--r--packages/SettingsLib/res/values/strings.xml24
-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/bluetooth/CachedBluetoothDevice.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java23
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java7
-rw-r--r--packages/SettingsProvider/res/values-or/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/dimens.xml8
-rw-r--r--packages/SystemUI/res/values/dimens.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt10
-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/NotificationPanelViewController.java152
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt92
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt97
-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--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java11
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto6
-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/BatteryExternalStatsWorker.java14
-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/audio/SpatializerHelper.java20
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java8
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java8
-rw-r--r--services/core/java/com/android/server/locales/LocaleManagerService.java34
-rw-r--r--services/core/java/com/android/server/locales/TEST_MAPPING9
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java17
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java56
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java57
-rw-r--r--services/core/java/com/android/server/pm/DexOptHelper.java4
-rw-r--r--services/core/java/com/android/server/pm/InitAppsHelper.java (renamed from services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java)203
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java30
-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/PackageManagerService.java24
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java2
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java4
-rw-r--r--services/core/java/com/android/server/pm/StorageEventHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java67
-rw-r--r--services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java6
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java19
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java22
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java71
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java2
-rw-r--r--services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java44
-rw-r--r--services/core/java/com/android/server/utils/TimingsTraceAndSlog.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java61
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java11
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java3
-rw-r--r--services/core/java/com/android/server/wm/ContentRecorder.java154
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java2
-rw-r--r--services/core/jni/gnss/MeasurementCorrections.cpp133
-rw-r--r--services/core/jni/gnss/MeasurementCorrections.h20
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java7
-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.java48
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java39
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java165
-rw-r--r--services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java75
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java59
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java145
-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
175 files changed, 4897 insertions, 1760 deletions
diff --git a/Android.bp b/Android.bp
index 753cefc38ed6..149b22355c58 100644
--- a/Android.bp
+++ b/Android.bp
@@ -97,6 +97,7 @@ filegroup {
":platform-compat-native-aidl",
// AIDL sources from external directories
+ ":android.hardware.gnss-V2-java-source",
":android.hardware.graphics.common-V3-java-source",
":android.hardware.security.keymint-V2-java-source",
":android.hardware.security.secureclock-V1-java-source",
@@ -328,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/core/api/current.txt b/core/api/current.txt
index 02c30e3b1722..5aae219400e2 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5815,6 +5815,7 @@ package android.app {
public class LocaleManager {
method @NonNull public android.os.LocaleList getApplicationLocales();
method @NonNull @RequiresPermission(value="android.permission.READ_APP_SPECIFIC_LOCALES", conditional=true) public android.os.LocaleList getApplicationLocales(@NonNull String);
+ method @NonNull public android.os.LocaleList getSystemLocales();
method public void setApplicationLocales(@NonNull android.os.LocaleList);
}
@@ -7465,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);
@@ -7706,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";
@@ -9736,8 +9740,8 @@ package android.content {
method @Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void removeStickyBroadcast(@RequiresPermission android.content.Intent);
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
- method public void revokeOwnPermissionOnKill(@NonNull String);
- method public void revokeOwnPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
+ method public void revokeSelfPermissionOnKill(@NonNull String);
+ method public void revokeSelfPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
method public abstract void revokeUriPermission(android.net.Uri, int);
method public abstract void revokeUriPermission(String, android.net.Uri, int);
method public abstract void sendBroadcast(@RequiresPermission android.content.Intent);
@@ -11244,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();
@@ -12305,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();
@@ -12320,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();
@@ -12345,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>);
@@ -22190,7 +22221,7 @@ package android.media {
field public static final String KEY_AAC_DRC_OUTPUT_LOUDNESS = "aac-drc-output-loudness";
field public static final String KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level";
field public static final String KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level";
- field public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
+ field @Deprecated public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
field public static final String KEY_AAC_PROFILE = "aac-profile";
field public static final String KEY_AAC_SBR_MODE = "aac-sbr-mode";
field public static final String KEY_ALLOW_FRAME_DROP = "allow-frame-drop";
@@ -26076,7 +26107,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>);
@@ -26134,6 +26165,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
@@ -26183,6 +26215,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);
@@ -26202,12 +26235,13 @@ package android.media.tv.interactive {
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);
@@ -26226,6 +26260,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);
@@ -26255,6 +26290,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);
@@ -26267,6 +26303,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);
@@ -26275,6 +26312,9 @@ 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_PRIVATE_KEY = "private_key";
}
public static interface TvInteractiveAppView.OnUnhandledInputEventListener {
@@ -26288,6 +26328,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);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5df988153752..c723fb757aee 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1079,6 +1079,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 +1090,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 +1102,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 +1148,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 +1162,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
@@ -5490,6 +5491,32 @@ package android.location {
method @NonNull public android.location.GnssCapabilities.Builder setHasSatellitePvt(boolean);
}
+ public final class GnssExcessPathInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @FloatRange(from=0.0f) public float getAttenuationDb();
+ method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
+ method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+ method @NonNull public android.location.GnssReflectingPlane getReflectingPlane();
+ method public boolean hasAttenuation();
+ method public boolean hasExcessPathLength();
+ method public boolean hasExcessPathLengthUncertainty();
+ method public boolean hasReflectingPlane();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssExcessPathInfo> CREATOR;
+ }
+
+ public static final class GnssExcessPathInfo.Builder {
+ ctor public GnssExcessPathInfo.Builder();
+ method @NonNull public android.location.GnssExcessPathInfo build();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearAttenuationDb();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthMeters();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthUncertaintyMeters();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setAttenuationDb(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+ }
+
public final class GnssMeasurement implements android.os.Parcelable {
method @Nullable public java.util.Collection<android.location.CorrelationVector> getCorrelationVectors();
method @Nullable public android.location.SatellitePvt getSatellitePvt();
@@ -5571,15 +5598,18 @@ package android.location {
public final class GnssSingleSatCorrection implements android.os.Parcelable {
method public int describeContents();
method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
+ method @FloatRange(from=0.0f) public float getCombinedAttenuationDb();
method public int getConstellationType();
method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+ method @NonNull public java.util.List<android.location.GnssExcessPathInfo> getGnssExcessPathInfoList();
method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
- method @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
+ method @Deprecated @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
method @IntRange(from=0) public int getSatelliteId();
+ method public boolean hasCombinedAttenuation();
method public boolean hasExcessPathLength();
method public boolean hasExcessPathLengthUncertainty();
- method public boolean hasReflectingPlane();
+ method @Deprecated public boolean hasReflectingPlane();
method public boolean hasValidSatelliteLineOfSight();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
@@ -5588,15 +5618,18 @@ package android.location {
public static final class GnssSingleSatCorrection.Builder {
ctor public GnssSingleSatCorrection.Builder();
method @NonNull public android.location.GnssSingleSatCorrection build();
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder clearCombinedAttenuationDb();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthMeters();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthUncertaintyMeters();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearProbabilityLineOfSight();
method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder setCombinedAttenuationDb(@FloatRange(from=0.0f) float);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder setGnssExcessPathInfoList(@NonNull java.util.List<android.location.GnssExcessPathInfo>);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
- method @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+ method @Deprecated @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int);
}
@@ -10049,9 +10082,9 @@ package android.permission {
method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String);
method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
- method @BinderThread public void onRevokeOwnPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
+ method @BinderThread public void onRevokeSelfPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
method @Deprecated @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull android.permission.AdminPermissionControlParams, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 2e8bed32665c..6260f6b8a3ca 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -300,7 +300,6 @@ package android.app {
}
public class LocaleManager {
- method @Nullable public android.os.LocaleList getSystemLocales();
method public void setSystemLocales(@NonNull android.os.LocaleList);
}
@@ -502,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();
@@ -2429,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/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f5eb1f6e24ed..ac46066997ff 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -77,6 +77,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
import android.system.ErrnoException;
import android.system.Os;
@@ -216,6 +217,12 @@ class ContextImpl extends Context {
@UnsupportedAppUsage
private @Nullable ClassLoader mClassLoader;
+ /**
+ * The {@link com.android.server.wm.WindowToken} representing this instance if it is
+ * {@link #CONTEXT_TYPE_WINDOW_CONTEXT} or {@link #CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI}.
+ * If the type is {@link #CONTEXT_TYPE_ACTIVITY}, then represents the
+ * {@link android.window.WindowContainerToken} of the activity.
+ */
private final @Nullable IBinder mToken;
private final @NonNull UserHandle mUser;
@@ -2180,8 +2187,9 @@ class ContextImpl extends Context {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- getSystemService(PermissionManager.class).revokeOwnPermissionsOnKill(permissions);
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+ getSystemService(PermissionControllerManager.class).revokeSelfPermissionsOnKill(
+ getPackageName(), new ArrayList<String>(permissions));
}
@Override
diff --git a/core/java/android/app/ILocaleManager.aidl b/core/java/android/app/ILocaleManager.aidl
index 348cb2d30739..3002c8bb9c3e 100644
--- a/core/java/android/app/ILocaleManager.aidl
+++ b/core/java/android/app/ILocaleManager.aidl
@@ -40,4 +40,9 @@ import android.os.LocaleList;
*/
LocaleList getApplicationLocales(String packageName, int userId);
+ /**
+ * Returns the current system locales.
+ */
+ LocaleList getSystemLocales();
+
} \ No newline at end of file
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index cedf483eb076..e9c29b8aa0a5 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -1103,9 +1103,12 @@ public class KeyguardManager {
}
/**
- * Registers a listener to execute when the keyguard visibility changes.
+ * Registers a listener to execute when the keyguard locked state changes.
*
- * @param listener The listener to add to receive keyguard visibility changes.
+ * @param listener The listener to add to receive keyguard locked state changes.
+ *
+ * @see #isKeyguardLocked()
+ * @see #removeKeyguardLockedStateListener(KeyguardLockedStateListener)
*/
@RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
public void addKeyguardLockedStateListener(@NonNull @CallbackExecutor Executor executor,
@@ -1124,7 +1127,12 @@ public class KeyguardManager {
}
/**
- * Unregisters a listener that executes when the keyguard visibility changes.
+ * Unregisters a listener that executes when the keyguard locked state changes.
+ *
+ * @param listener The listener to remove.
+ *
+ * @see #isKeyguardLocked()
+ * @see #addKeyguardLockedStateListener(Executor, KeyguardLockedStateListener)
*/
@RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
public void removeKeyguardLockedStateListener(@NonNull KeyguardLockedStateListener listener) {
diff --git a/core/java/android/app/LocaleManager.java b/core/java/android/app/LocaleManager.java
index 522dc845f57c..efe9e35d4c64 100644
--- a/core/java/android/app/LocaleManager.java
+++ b/core/java/android/app/LocaleManager.java
@@ -18,7 +18,6 @@ package android.app;
import android.Manifest;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -127,31 +126,36 @@ public class LocaleManager {
}
/**
- * Sets the current system locales to the provided value.
+ * Returns the current system locales, ignoring app-specific overrides.
*
- * @hide
+ * <p><b>Note:</b> Apps should generally access the user's locale preferences as indicated in
+ * their in-process {@link LocaleList}s. However, in case an app-specific locale is set, this
+ * method helps cater to rare use-cases which might require specifically knowing the system
+ * locale.
+ *
+ * <p><b>Note:</b> This API is not user-aware. It returns the system locales for the foreground
+ * user.
*/
- @TestApi
- public void setSystemLocales(@NonNull LocaleList locales) {
+ @NonNull
+ public LocaleList getSystemLocales() {
try {
- Configuration conf = ActivityManager.getService().getConfiguration();
- conf.setLocales(locales);
- ActivityManager.getService().updatePersistentConfiguration(conf);
+ return mService.getSystemLocales();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Returns the current system locales for the device.
+ * Sets the current system locales to the provided value.
*
* @hide
*/
@TestApi
- @Nullable
- public LocaleList getSystemLocales() {
+ public void setSystemLocales(@NonNull LocaleList locales) {
try {
- return ActivityManager.getService().getConfiguration().getLocales();
+ Configuration conf = ActivityManager.getService().getConfiguration();
+ conf.setLocales(locales);
+ ActivityManager.getService().updatePersistentConfiguration(conf);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
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..0f9b4e381145 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
@@ -14800,6 +14864,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 +15350,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 +15659,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 +15672,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 +15684,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 +15732,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 +15817,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/FactoryResetProtectionPolicy.java b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
index 40ae1f0c11ea..7e951779d2a6 100644
--- a/core/java/android/app/admin/FactoryResetProtectionPolicy.java
+++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -254,4 +255,18 @@ public final class FactoryResetProtectionPolicy implements Parcelable {
return !mFactoryResetProtectionAccounts.isEmpty() && mFactoryResetProtectionEnabled;
}
+ /**
+ * @hide
+ */
+ public void dump(IndentingPrintWriter pw) {
+ pw.print("factoryResetProtectionEnabled=");
+ pw.println(mFactoryResetProtectionEnabled);
+
+ pw.print("factoryResetProtectionAccounts=");
+ pw.increaseIndent();
+ for (int i = 0; i < mFactoryResetProtectionAccounts.size(); i++) {
+ pw.println(mFactoryResetProtectionAccounts.get(i));
+ }
+ pw.decreaseIndent();
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index fb1ca41ccc56..471c2a8630c1 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;
@@ -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/BroadcastResponseStats.java b/core/java/android/app/usage/BroadcastResponseStats.java
index e1d37e1b1ae0..572c45355e42 100644
--- a/core/java/android/app/usage/BroadcastResponseStats.java
+++ b/core/java/android/app/usage/BroadcastResponseStats.java
@@ -29,6 +29,8 @@ import java.util.Objects;
* Class containing a collection of stats related to response events started from an app
* after receiving a broadcast.
*
+ * @see UsageStatsManager#queryBroadcastResponseStats(String, long)
+ * @see UsageStatsManager#clearBroadcastResponseStats(String, long)
* @hide
*/
@SystemApi
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 60efb4d3ec81..24b1b6adb450 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6508,22 +6508,22 @@ public abstract class Context {
/**
- * Triggers the asynchronous revocation of a permission.
+ * Triggers the asynchronous revocation of a runtime permission. If the permission is not
+ * currently granted, nothing happens (even if later granted by the user).
*
* @param permName The name of the permission to be revoked.
- * @see #revokeOwnPermissionsOnKill(Collection)
+ * @see #revokeSelfPermissionsOnKill(Collection)
+ * @throws IllegalArgumentException if the permission is not a runtime permission
*/
- public void revokeOwnPermissionOnKill(@NonNull String permName) {
- revokeOwnPermissionsOnKill(Collections.singletonList(permName));
+ public void revokeSelfPermissionOnKill(@NonNull String permName) {
+ revokeSelfPermissionsOnKill(Collections.singletonList(permName));
}
/**
* Triggers the revocation of one or more permissions for the calling package. A package is only
- * able to revoke a permission under the following conditions:
- * <ul>
- * <li>Each permission in {@code permissions} must be granted to the calling package.
- * <li>Each permission in {@code permissions} must be a runtime permission.
- * </ul>
+ * able to revoke runtime permissions. If a permission is not currently granted, it is ignored
+ * and will not get revoked (even if later granted by the user). Ultimately, you should never
+ * make assumptions about a permission status as users may grant or revoke them at any time.
* <p>
* Background permissions which have no corresponding foreground permission still granted once
* the revocation is effective will also be revoked.
@@ -6549,8 +6549,9 @@ public abstract class Context {
* @param permissions Collection of permissions to be revoked.
* @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
* @see PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)
+ * @throws IllegalArgumentException if any of the permissions is not a runtime permission
*/
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
@@ -7145,8 +7146,9 @@ public abstract class Context {
}
/**
- * Returns token if the {@link Context} is a {@link android.app.WindowContext}. Returns
- * {@code null} otherwise.
+ * Returns the {@link IBinder} representing the associated
+ * {@link com.android.server.wm.WindowToken} if the {@link Context} is a
+ * {@link android.app.WindowContext}. Returns {@code null} otherwise.
*
* @hide
*/
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 9adf17367039..4ecd7761ac4f 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1036,8 +1036,8 @@ public class ContextWrapper extends Context {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- mBase.revokeOwnPermissionsOnKill(permissions);
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+ mBase.revokeSelfPermissionsOnKill(permissions);
}
@Override
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/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/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/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index c9dd06cfaa43..e3f02e73a41f 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -59,6 +59,6 @@ oneway interface IPermissionController {
void getHibernationEligibility(
in String packageName,
in AndroidFuture callback);
- void revokeOwnPermissionsOnKill(in String packageName, in List<String> permissions,
+ void revokeSelfPermissionsOnKill(in String packageName, in List<String> permissions,
in AndroidFuture callback);
}
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 619c8705ddae..6a93b354f4da 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -76,8 +76,6 @@ interface IPermissionManager {
List<SplitPermissionInfoParcelable> getSplitPermissions();
- void revokeOwnPermissionsOnKill(String packageName, in List<String> permissions);
-
void startOneTimePermissionSession(String packageName, int userId, long timeout,
long revokeAfterKilledDelay, int importanceToResetTimer,
int importanceToKeepSessionAlive);
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index a005ab4e6ac7..3c2c7f03761b 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -916,15 +916,15 @@ public final class PermissionControllerManager {
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
*
- * @see Context#revokeOwnPermissionsOnKill(java.util.Collection)
+ * @see Context#revokeSelfPermissionsOnKill(java.util.Collection)
*
* @hide
*/
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void revokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions) {
mRemoteService.postAsync(service -> {
AndroidFuture<Void> callback = new AndroidFuture<>();
- service.revokeOwnPermissionsOnKill(packageName, permissions, callback);
+ service.revokeSelfPermissionsOnKill(packageName, permissions, callback);
return callback;
}).whenComplete((result, err) -> {
if (err != null) {
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 3292e7110ee5..4efffc5a11ef 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -40,6 +40,7 @@ import android.compat.annotation.Disabled;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -339,10 +340,10 @@ public abstract class PermissionControllerService extends Service {
* @param permissions List of permissions to be revoked.
* @param callback Callback waiting for operation to be complete.
*
- * @see PermissionManager#revokeOwnPermissionsOnKill(java.util.Collection)
+ * @see android.content.Context#revokeSelfPermissionsOnKill(java.util.Collection)
*/
@BinderThread
- public void onRevokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void onRevokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull Runnable callback) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
@@ -703,13 +704,19 @@ public abstract class PermissionControllerService extends Service {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void revokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull AndroidFuture callback) {
try {
- enforceSomePermissionsGrantedToCaller(
- Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
Objects.requireNonNull(callback);
- onRevokeOwnPermissionsOnKill(packageName, permissions,
+
+ final int callingUid = Binder.getCallingUid();
+ int targetPackageUid = getPackageManager().getPackageUid(packageName,
+ PackageManager.PackageInfoFlags.of(0));
+ if (targetPackageUid != callingUid) {
+ enforceSomePermissionsGrantedToCaller(
+ Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
+ }
+ onRevokeSelfPermissionsOnKill(packageName, permissions,
() -> callback.complete(null));
} catch (Throwable t) {
callback.completeExceptionally(t);
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index c509de6bb5e1..7a797ce28870 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -76,7 +76,6 @@ import com.android.internal.annotations.Immutable;
import com.android.internal.util.CollectionUtils;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -626,19 +625,6 @@ public final class PermissionManager {
}
/**
- * @see Context#revokeOwnPermissionsOnKill(Collection)
- * @hide
- */
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- try {
- mPermissionManager.revokeOwnPermissionsOnKill(mContext.getPackageName(),
- new ArrayList<String>(permissions));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Gets the state flags associated with a permission.
*
* @param packageName the package name for which to get the flags
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/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/util/TimingsTraceLog.java b/core/java/android/util/TimingsTraceLog.java
index 066709fd8744..48a5ceae1aef 100644
--- a/core/java/android/util/TimingsTraceLog.java
+++ b/core/java/android/util/TimingsTraceLog.java
@@ -147,7 +147,7 @@ public class TimingsTraceLog {
* Logs a duration so it can be parsed by external tools for performance reporting.
*/
public void logDuration(String name, long timeMs) {
- Slog.d(mTag, name + " took to complete: " + timeMs + "ms");
+ Slog.v(mTag, name + " took to complete: " + timeMs + "ms");
}
/**
diff --git a/core/java/android/view/ContentRecordingSession.java b/core/java/android/view/ContentRecordingSession.java
index db4ec1155e64..c66c70af0656 100644
--- a/core/java/android/view/ContentRecordingSession.java
+++ b/core/java/android/view/ContentRecordingSession.java
@@ -66,10 +66,11 @@ public final class ContentRecordingSession implements Parcelable {
private int mContentToRecord = RECORD_CONTENT_DISPLAY;
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@VisibleForTesting
@Nullable
@@ -192,10 +193,11 @@ public final class ContentRecordingSession implements Parcelable {
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @VisibleForTesting @Nullable IBinder getTokenToRecord() {
@@ -231,10 +233,11 @@ public final class ContentRecordingSession implements Parcelable {
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @NonNull ContentRecordingSession setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -390,10 +393,11 @@ public final class ContentRecordingSession implements Parcelable {
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @NonNull Builder setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -433,7 +437,7 @@ public final class ContentRecordingSession implements Parcelable {
}
@DataClass.Generated(
- time = 1644843382972L,
+ time = 1645803878639L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/ContentRecordingSession.java",
inputSignatures = "public static final int RECORD_CONTENT_DISPLAY\npublic static final int RECORD_CONTENT_TASK\nprivate int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @com.android.internal.annotations.VisibleForTesting @android.annotation.Nullable android.os.IBinder mTokenToRecord\npublic static android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static boolean isValid(android.view.ContentRecordingSession)\npublic static boolean isSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)")
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/KernelAllocationStats.java b/core/java/com/android/internal/os/KernelAllocationStats.java
index 1c3f8b0bf095..58d51e327ade 100644
--- a/core/java/com/android/internal/os/KernelAllocationStats.java
+++ b/core/java/com/android/internal/os/KernelAllocationStats.java
@@ -24,21 +24,29 @@ public final class KernelAllocationStats {
/** Process dma-buf stats. */
public static final class ProcessDmabuf {
+ public final int uid;
+ public final String processName;
+ public final int oomScore;
+
/** Size of buffers retained by the process. */
public final int retainedSizeKb;
/** Number of buffers retained by the process. */
public final int retainedBuffersCount;
- /** Size of buffers mapped to the address space. */
- public final int mappedSizeKb;
- /** Count of buffers mapped to the address space. */
- public final int mappedBuffersCount;
+ /** Size of buffers shared with Surface Flinger. */
+ public final int surfaceFlingerSizeKb;
+ /** Count of buffers shared with Surface Flinger. */
+ public final int surfaceFlingerCount;
- ProcessDmabuf(int retainedSizeKb, int retainedBuffersCount,
- int mappedSizeKb, int mappedBuffersCount) {
+ ProcessDmabuf(int uid, String processName, int oomScore, int retainedSizeKb,
+ int retainedBuffersCount, int surfaceFlingerSizeKb,
+ int surfaceFlingerCount) {
+ this.uid = uid;
+ this.processName = processName;
+ this.oomScore = oomScore;
this.retainedSizeKb = retainedSizeKb;
this.retainedBuffersCount = retainedBuffersCount;
- this.mappedSizeKb = mappedSizeKb;
- this.mappedBuffersCount = mappedBuffersCount;
+ this.surfaceFlingerSizeKb = surfaceFlingerSizeKb;
+ this.surfaceFlingerCount = surfaceFlingerCount;
}
}
@@ -47,7 +55,7 @@ public final class KernelAllocationStats {
* stats could not be read.
*/
@Nullable
- public static native ProcessDmabuf getDmabufAllocations(int pid);
+ public static native ProcessDmabuf[] getDmabufAllocations();
/** Pid to gpu memory size. */
public static final class ProcessGpuMem {
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index cc7e9d95b4f8..e281853d31bf 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -34,6 +34,7 @@ import android.os.Trace;
import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.permission.PermissionManager.SplitPermissionInfo;
+import android.sysprop.ApexProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1187,7 +1188,8 @@ public class SystemConfig {
boolean systemExt = permFile.toPath().startsWith(
Environment.getSystemExtDirectory().toPath() + "/");
boolean apex = permFile.toPath().startsWith(
- Environment.getApexDirectory().toPath() + "/");
+ Environment.getApexDirectory().toPath() + "/")
+ && ApexProperties.updatable().orElse(false);
if (vendor) {
readPrivAppPermissions(parser, mVendorPrivAppPermissions,
mVendorPrivAppDenyPermissions);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 3a76745cc4d9..a1be88440c97 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -272,6 +272,7 @@ cc_library_shared {
"libinput",
"libcamera_client",
"libcamera_metadata",
+ "libprocinfo",
"libsqlite",
"libEGL",
"libGLESv1_CM",
diff --git a/core/jni/com_android_internal_os_KernelAllocationStats.cpp b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
index e0a24430e739..5b104977f1d8 100644
--- a/core/jni/com_android_internal_os_KernelAllocationStats.cpp
+++ b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
@@ -13,12 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <dmabufinfo/dmabufinfo.h>
#include <jni.h>
#include <meminfo/sysmeminfo.h>
+#include <procinfo/process.h>
#include "core_jni_helpers.h"
+using DmaBuffer = ::android::dmabufinfo::DmaBuffer;
+using android::base::ReadFileToString;
+using android::base::StringPrintf;
+
namespace {
static jclass gProcessDmabufClazz;
static jmethodID gProcessDmabufCtor;
@@ -28,30 +35,127 @@ static jmethodID gProcessGpuMemCtor;
namespace android {
-static jobject KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject, jint pid) {
- std::vector<dmabufinfo::DmaBuffer> buffers;
- if (!dmabufinfo::ReadDmaBufMapRefs(pid, &buffers)) {
+struct PidDmaInfo {
+ uid_t uid;
+ std::string cmdline;
+ int oomScoreAdj;
+};
+
+static jobjectArray KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject) {
+ std::vector<DmaBuffer> buffers;
+
+ if (!dmabufinfo::ReadDmaBufs(&buffers)) {
return nullptr;
}
- jint mappedSize = 0;
- jint mappedCount = buffers.size();
- for (const auto &buffer : buffers) {
- mappedSize += buffer.size();
+
+ // Create a reverse map from pid to dmabufs
+ // Store dmabuf inodes & sizes for later processing.
+ std::unordered_map<pid_t, std::set<ino_t>> pidToInodes;
+ std::unordered_map<ino_t, long> inodeToSize;
+ for (auto &buf : buffers) {
+ for (auto pid : buf.pids()) {
+ pidToInodes[pid].insert(buf.inode());
+ }
+ inodeToSize[buf.inode()] = buf.size();
+ }
+
+ pid_t surfaceFlingerPid = -1;
+ // The set of all inodes that are being retained by SurfaceFlinger. Buffers
+ // shared between another process and SF will appear in this set.
+ std::set<ino_t> surfaceFlingerBufferInodes;
+ // The set of all inodes that are being retained by any process other
+ // than SurfaceFlinger. Buffers shared between another process and SF will
+ // appear in this set.
+ std::set<ino_t> otherProcessBufferInodes;
+
+ // Find SurfaceFlinger pid & get cmdlines, oomScoreAdj, etc for each pid
+ // holding any DMA buffers.
+ std::unordered_map<pid_t, PidDmaInfo> pidDmaInfos;
+ for (const auto &pidToInodeEntry : pidToInodes) {
+ pid_t pid = pidToInodeEntry.first;
+
+ android::procinfo::ProcessInfo processInfo;
+ if (!android::procinfo::GetProcessInfo(pid, &processInfo)) {
+ continue;
+ }
+
+ std::string cmdline;
+ if (!ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &cmdline)) {
+ continue;
+ }
+
+ // cmdline strings are null-delimited, so we split on \0 here
+ if (cmdline.substr(0, cmdline.find('\0')) == "/system/bin/surfaceflinger") {
+ if (surfaceFlingerPid == -1) {
+ surfaceFlingerPid = pid;
+ surfaceFlingerBufferInodes = pidToInodes[pid];
+ } else {
+ LOG(ERROR) << "getDmabufAllocations found multiple SF processes; pid1: " << pid
+ << ", pid2:" << surfaceFlingerPid;
+ surfaceFlingerPid = -2; // Used as a sentinel value below
+ }
+ } else {
+ otherProcessBufferInodes.insert(pidToInodes[pid].begin(), pidToInodes[pid].end());
+ }
+
+ std::string oomScoreAdjStr;
+ if (!ReadFileToString(StringPrintf("/proc/%d/oom_score_adj", pid), &oomScoreAdjStr)) {
+ continue;
+ }
+
+ pidDmaInfos[pid] = PidDmaInfo{.uid = processInfo.uid,
+ .cmdline = cmdline,
+ .oomScoreAdj = atoi(oomScoreAdjStr.c_str())};
+ }
+
+ if (surfaceFlingerPid < 0) {
+ LOG(ERROR) << "getDmabufAllocations could not identify SurfaceFlinger "
+ << "process via /proc/pid/cmdline";
}
- mappedSize /= 1024;
-
- jint retainedSize = -1;
- jint retainedCount = -1;
- if (dmabufinfo::ReadDmaBufFdRefs(pid, &buffers)) {
- retainedCount = buffers.size();
- retainedSize = 0;
- for (const auto &buffer : buffers) {
- retainedSize += buffer.size();
+
+ jobjectArray ret = env->NewObjectArray(pidDmaInfos.size(), gProcessDmabufClazz, NULL);
+ int retArrayIndex = 0;
+ for (const auto &pidDmaInfosEntry : pidDmaInfos) {
+ pid_t pid = pidDmaInfosEntry.first;
+
+ // For all processes apart from SurfaceFlinger, this set will store the
+ // dmabuf inodes that are shared with SF. For SF, it will store the inodes
+ // that are shared with any other process.
+ std::set<ino_t> sharedBuffers;
+ if (pid == surfaceFlingerPid) {
+ set_intersection(surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+ otherProcessBufferInodes.begin(), otherProcessBufferInodes.end(),
+ std::inserter(sharedBuffers, sharedBuffers.end()));
+ } else if (surfaceFlingerPid > 0) {
+ set_intersection(pidToInodes[pid].begin(), pidToInodes[pid].end(),
+ surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+ std::inserter(sharedBuffers, sharedBuffers.begin()));
+ } // If surfaceFlingerPid < 0; it means we failed to identify it, and
+ // the SF-related fields below should be left empty.
+
+ long totalSize = 0;
+ long sharedBuffersSize = 0;
+ for (const auto &inode : pidToInodes[pid]) {
+ totalSize += inodeToSize[inode];
+ if (sharedBuffers.count(inode)) {
+ sharedBuffersSize += inodeToSize[inode];
+ }
}
- retainedSize /= 1024;
+
+ jobject obj = env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor,
+ /* uid */ pidDmaInfos[pid].uid,
+ /* process name */
+ env->NewStringUTF(pidDmaInfos[pid].cmdline.c_str()),
+ /* oomscore */ pidDmaInfos[pid].oomScoreAdj,
+ /* retainedSize */ totalSize / 1024,
+ /* retainedCount */ pidToInodes[pid].size(),
+ /* sharedWithSurfaceFlinger size */ sharedBuffersSize / 1024,
+ /* sharedWithSurfaceFlinger count */ sharedBuffers.size());
+
+ env->SetObjectArrayElement(ret, retArrayIndex++, obj);
}
- return env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor, retainedSize, retainedCount,
- mappedSize, mappedCount);
+
+ return ret;
}
static jobject KernelAllocationStats_getGpuAllocations(JNIEnv *env) {
@@ -74,7 +178,7 @@ static jobject KernelAllocationStats_getGpuAllocations(JNIEnv *env) {
}
static const JNINativeMethod methods[] = {
- {"getDmabufAllocations", "(I)Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
+ {"getDmabufAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
(void *)KernelAllocationStats_getDmabufAllocations},
{"getGpuAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessGpuMem;",
(void *)KernelAllocationStats_getGpuAllocations},
@@ -86,7 +190,8 @@ int register_com_android_internal_os_KernelAllocationStats(JNIEnv *env) {
jclass clazz =
FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessDmabuf");
gProcessDmabufClazz = MakeGlobalRefOrDie(env, clazz);
- gProcessDmabufCtor = GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(IIII)V");
+ gProcessDmabufCtor =
+ GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(ILjava/lang/String;IIIII)V");
clazz = FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessGpuMem");
gProcessGpuMemClazz = MakeGlobalRefOrDie(env, clazz);
@@ -94,4 +199,4 @@ int register_com_android_internal_os_KernelAllocationStats(JNIEnv *env) {
return res;
}
-} // namespace android
+} // namespace android \ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d652b2ff4f4a..5551e46531ed 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" />
@@ -724,6 +725,7 @@
<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 -->
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/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/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
index 5dc44d21c6b7..8de919681006 100644
--- a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
+++ b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
@@ -123,7 +123,7 @@ public class TimingsTraceLogTest {
public void testLogDuration() throws Exception {
TimingsTraceLog log = new TimingsTraceLog(TAG, TRACE_TAG_APP, 10);
log.logDuration("logro", 42);
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), contains("logro took to complete: 42ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
}
@Test
@@ -134,7 +134,7 @@ public class TimingsTraceLogTest {
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("test took to complete: \\dms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
}
@Test
@@ -149,8 +149,8 @@ public class TimingsTraceLogTest {
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
}
@Test
@@ -170,9 +170,9 @@ public class TimingsTraceLogTest {
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L3"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(3));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L3 took to complete: \\d+ms")),
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L3 took to complete: \\d+ms")),
never());
verify((MockedVoidMethod) () -> Slog.w(TAG, "not tracing duration of 'L3' "
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index e898f570a6b8..4449c48d28bb 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2257,6 +2257,12 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/TransitionController.java"
},
+ "264036181": {
+ "message": "Unable to retrieve task to start recording for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"269576220": {
"message": "Resuming rotation after drag",
"level": "DEBUG",
@@ -2761,6 +2767,12 @@
"group": "WM_DEBUG_WALLPAPER",
"at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
},
+ "736003885": {
+ "message": "Unable to retrieve the task token to start recording for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"736692676": {
"message": "Config is relaunching %s",
"level": "VERBOSE",
@@ -2791,6 +2803,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "778774915": {
+ "message": "Unable to record task since feature is disabled %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"781471998": {
"message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
"level": "WARN",
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/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index dd272cd5ff7d..c24cabb287de 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -310,6 +310,11 @@ bool HardwareBitmapUploader::has1010102Support() {
return has101012Support;
}
+bool HardwareBitmapUploader::hasAlpha8Support() {
+ static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
+ return hasAlpha8Support;
+}
+
static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
FormatInfo formatInfo;
switch (skBitmap.info().colorType()) {
@@ -363,6 +368,13 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
}
formatInfo.format = GL_RGBA;
break;
+ case kAlpha_8_SkColorType:
+ formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
+ formatInfo.format = GL_R8;
+ formatInfo.type = GL_UNSIGNED_BYTE;
+ formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
+ break;
default:
ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
formatInfo.valid = false;
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 34f43cd8a198..81057a24c29c 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -30,11 +30,13 @@ public:
#ifdef __ANDROID__
static bool hasFP16Support();
static bool has1010102Support();
+ static bool hasAlpha8Support();
#else
static bool hasFP16Support() {
return true;
}
static bool has1010102Support() { return true; }
+ static bool hasAlpha8Support() { return true; }
#endif
};
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 1a89cfd5d0ad..67f47580a70f 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -104,6 +104,10 @@ sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info,
sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
+ if (bitmap.colorType() == kAlpha_8_SkColorType &&
+ !uirenderer::HardwareBitmapUploader::hasAlpha8Support()) {
+ return nullptr;
+ }
return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
#else
return Bitmap::allocateHeapBitmap(bitmap.info());
diff --git a/location/java/android/location/GnssExcessPathInfo.java b/location/java/android/location/GnssExcessPathInfo.java
new file mode 100644
index 000000000000..72b2374bad8f
--- /dev/null
+++ b/location/java/android/location/GnssExcessPathInfo.java
@@ -0,0 +1,375 @@
+/*
+ * 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.location;
+
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Contains the info of an excess path signal caused by reflection
+ *
+ * @hide
+ */
+@SystemApi
+public final class GnssExcessPathInfo implements Parcelable {
+
+ private static final int HAS_EXCESS_PATH_LENGTH_MASK = EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+ private static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK =
+ EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+ private static final int HAS_REFLECTING_PLANE_MASK = EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+ private static final int HAS_ATTENUATION_MASK = EXCESS_PATH_INFO_HAS_ATTENUATION;
+
+ /* A bitmask of fields present in this object (see HAS_* constants defined above) */
+ private final int mFlags;
+ private final float mExcessPathLengthMeters;
+ private final float mExcessPathLengthUncertaintyMeters;
+ @Nullable
+ private final GnssReflectingPlane mReflectingPlane;
+ private final float mAttenuationDb;
+
+ private GnssExcessPathInfo(
+ int flags,
+ float excessPathLengthMeters,
+ float excessPathLengthUncertaintyMeters,
+ @Nullable GnssReflectingPlane reflectingPlane,
+ float attenuationDb) {
+ mFlags = flags;
+ mExcessPathLengthMeters = excessPathLengthMeters;
+ mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mReflectingPlane = reflectingPlane;
+ mAttenuationDb = attenuationDb;
+ }
+
+ /**
+ * Gets a bitmask of fields present in this object.
+ *
+ * <p>This API exists for JNI since it is easier for JNI to get one integer flag than looking up
+ * several has* methods.
+ * @hide
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
+ public boolean hasExcessPathLength() {
+ return (mFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+ }
+
+ /**
+ * Returns the excess path length to be subtracted from pseudorange before using it in
+ * calculating location.
+ *
+ * <p>{@link #hasExcessPathLength()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getExcessPathLengthMeters() {
+ if (!hasExcessPathLength()) {
+ throw new UnsupportedOperationException(
+ "getExcessPathLengthMeters() is not supported when hasExcessPathLength() is "
+ + "false");
+ }
+ return mExcessPathLengthMeters;
+ }
+
+ /** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
+ public boolean hasExcessPathLengthUncertainty() {
+ return (mFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+ }
+
+ /**
+ * Returns the error estimate (1-sigma) for the excess path length estimate.
+ *
+ * <p>{@link #hasExcessPathLengthUncertainty()} must be true when calling this method.
+ * Otherwise, an {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getExcessPathLengthUncertaintyMeters() {
+ if (!hasExcessPathLengthUncertainty()) {
+ throw new UnsupportedOperationException(
+ "getExcessPathLengthUncertaintyMeters() is not supported when "
+ + "hasExcessPathLengthUncertainty() is false");
+ }
+ return mExcessPathLengthUncertaintyMeters;
+ }
+
+ /**
+ * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+ *
+ * <p>Returns false if the satellite signal goes through multiple reflections or if reflection
+ * plane serving is not supported.
+ */
+ public boolean hasReflectingPlane() {
+ return (mFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+ }
+
+ /**
+ * Returns the reflecting plane characteristics at which the signal has bounced.
+ *
+ * <p>{@link #hasReflectingPlane()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @NonNull
+ public GnssReflectingPlane getReflectingPlane() {
+ if (!hasReflectingPlane()) {
+ throw new UnsupportedOperationException(
+ "getReflectingPlane() is not supported when hasReflectingPlane() is false");
+ }
+ return mReflectingPlane;
+ }
+
+ /** Returns {@code true} if {@link #getAttenuationDb()} is valid. */
+ public boolean hasAttenuation() {
+ return (mFlags & HAS_ATTENUATION_MASK) != 0;
+ }
+
+ /**
+ * Returns the expected reduction of signal strength of this path in non-negative dB.
+ *
+ * <p>{@link #hasAttenuation()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getAttenuationDb() {
+ if (!hasAttenuation()) {
+ throw new UnsupportedOperationException(
+ "getAttenuationDb() is not supported when hasAttenuation() is false");
+ }
+ return mAttenuationDb;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int parcelFlags) {
+ parcel.writeInt(mFlags);
+ if (hasExcessPathLength()) {
+ parcel.writeFloat(mExcessPathLengthMeters);
+ }
+ if (hasExcessPathLengthUncertainty()) {
+ parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+ }
+ if (hasReflectingPlane()) {
+ mReflectingPlane.writeToParcel(parcel, parcelFlags);
+ }
+ if (hasAttenuation()) {
+ parcel.writeFloat(mAttenuationDb);
+ }
+ }
+
+ public static final @NonNull Creator<GnssExcessPathInfo> CREATOR =
+ new Creator<GnssExcessPathInfo>() {
+ @Override
+ @NonNull
+ public GnssExcessPathInfo createFromParcel(@NonNull Parcel parcel) {
+ int flags = parcel.readInt();
+ float excessPathLengthMeters =
+ (flags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+ ? parcel.readFloat() : 0;
+ float excessPathLengthUncertaintyMeters =
+ (flags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+ ? parcel.readFloat() : 0;
+ GnssReflectingPlane reflectingPlane =
+ (flags & HAS_REFLECTING_PLANE_MASK) != 0
+ ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+ float attenuationDb =
+ (flags & HAS_ATTENUATION_MASK) != 0
+ ? parcel.readFloat() : 0;
+ return new GnssExcessPathInfo(flags, excessPathLengthMeters,
+ excessPathLengthUncertaintyMeters, reflectingPlane, attenuationDb);
+ }
+
+ @Override
+ public GnssExcessPathInfo[] newArray(int i) {
+ return new GnssExcessPathInfo[i];
+ }
+ };
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof GnssExcessPathInfo) {
+ GnssExcessPathInfo that = (GnssExcessPathInfo) obj;
+ return this.mFlags == that.mFlags
+ && (!hasExcessPathLength() || Float.compare(this.mExcessPathLengthMeters,
+ that.mExcessPathLengthMeters) == 0)
+ && (!hasExcessPathLengthUncertainty() || Float.compare(
+ this.mExcessPathLengthUncertaintyMeters,
+ that.mExcessPathLengthUncertaintyMeters) == 0)
+ && (!hasReflectingPlane() || Objects.equals(this.mReflectingPlane,
+ that.mReflectingPlane))
+ && (!hasAttenuation() || Float.compare(this.mAttenuationDb,
+ that.mAttenuationDb) == 0);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFlags,
+ mExcessPathLengthMeters,
+ mExcessPathLengthUncertaintyMeters,
+ mReflectingPlane,
+ mAttenuationDb);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("GnssExcessPathInfo[");
+ if (hasExcessPathLength()) {
+ builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+ }
+ if (hasExcessPathLengthUncertainty()) {
+ builder.append(" ExcessPathLengthUncertaintyMeters=").append(
+ mExcessPathLengthUncertaintyMeters);
+ }
+ if (hasReflectingPlane()) {
+ builder.append(" ReflectingPlane=").append(mReflectingPlane);
+ }
+ if (hasAttenuation()) {
+ builder.append(" AttenuationDb=").append(mAttenuationDb);
+ }
+ builder.append(']');
+ return builder.toString();
+ }
+
+ /** Builder for {@link GnssExcessPathInfo}. */
+ public static final class Builder {
+ private int mFlags;
+ private float mExcessPathLengthMeters;
+ private float mExcessPathLengthUncertaintyMeters;
+ @Nullable
+ private GnssReflectingPlane mReflectingPlane;
+ private float mAttenuationDb;
+
+ /** Constructor for {@link Builder}. */
+ public Builder() {}
+
+ /**
+ * Sets the excess path length to be subtracted from pseudorange before using it in
+ * calculating location.
+ */
+ @NonNull
+ public Builder setExcessPathLengthMeters(
+ @FloatRange(from = 0.0f) float excessPathLengthMeters) {
+ Preconditions.checkArgumentInRange(excessPathLengthMeters, 0, Float.MAX_VALUE,
+ "excessPathLengthMeters");
+ mExcessPathLengthMeters = excessPathLengthMeters;
+ mFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the excess path length.
+ *
+ * <p>This is to negate {@link #setExcessPathLengthMeters} call.
+ */
+ @NonNull
+ public Builder clearExcessPathLengthMeters() {
+ mExcessPathLengthMeters = 0;
+ mFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+ return this;
+ }
+
+ /** Sets the error estimate (1-sigma) for the excess path length estimate */
+ @NonNull
+ public Builder setExcessPathLengthUncertaintyMeters(
+ @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
+ Preconditions.checkArgumentInRange(excessPathLengthUncertaintyMeters, 0,
+ Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+ mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the error estimate (1-sigma) for the excess path length estimate
+ *
+ * <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
+ */
+ @NonNull
+ public Builder clearExcessPathLengthUncertaintyMeters() {
+ mExcessPathLengthUncertaintyMeters = 0;
+ mFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ return this;
+ }
+
+ /** Sets the reflecting plane information */
+ @NonNull
+ public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
+ mReflectingPlane = reflectingPlane;
+ if (reflectingPlane != null) {
+ mFlags |= HAS_REFLECTING_PLANE_MASK;
+ } else {
+ mFlags &= ~HAS_REFLECTING_PLANE_MASK;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the attenuation value in dB.
+ */
+ @NonNull
+ public Builder setAttenuationDb(@FloatRange(from = 0.0f) float attenuationDb) {
+ Preconditions.checkArgumentInRange(attenuationDb, 0, Float.MAX_VALUE,
+ "attenuationDb");
+ mAttenuationDb = attenuationDb;
+ mFlags |= HAS_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the attenuation value in dB.
+ *
+ * <p>This is to negate {@link #setAttenuationDb(float)} call.
+ */
+ @NonNull
+ public Builder clearAttenuationDb() {
+ mAttenuationDb = 0;
+ mFlags &= ~HAS_ATTENUATION_MASK;
+ return this;
+ }
+
+ /** Builds a {@link GnssExcessPathInfo} instance as specified by this builder. */
+ @NonNull
+ public GnssExcessPathInfo build() {
+ return new GnssExcessPathInfo(
+ mFlags,
+ mExcessPathLengthMeters,
+ mExcessPathLengthUncertaintyMeters,
+ mReflectingPlane,
+ mAttenuationDb);
+ }
+ }
+}
diff --git a/location/java/android/location/GnssReflectingPlane.java b/location/java/android/location/GnssReflectingPlane.java
index 1acdd1ecce0b..115cbec5e4de 100644
--- a/location/java/android/location/GnssReflectingPlane.java
+++ b/location/java/android/location/GnssReflectingPlane.java
@@ -22,9 +22,14 @@ import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* Holds the characteristics of the reflecting plane that a satellite signal has bounced from.
*
+ * <p>Starting with Android T, this class supports {@link #equals} and {@link #hashCode}, which
+ * are not supported before that.
+ *
* @hide
*/
@SystemApi
@@ -107,24 +112,41 @@ public final class GnssReflectingPlane implements Parcelable {
}
};
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeDouble(mLatitudeDegrees);
+ parcel.writeDouble(mLongitudeDegrees);
+ parcel.writeDouble(mAltitudeMeters);
+ parcel.writeDouble(mAzimuthDegrees);
+ }
+
@NonNull
@Override
public String toString() {
- final String format = " %-29s = %s\n";
- StringBuilder builder = new StringBuilder("ReflectingPlane:\n");
- builder.append(String.format(format, "LatitudeDegrees = ", mLatitudeDegrees));
- builder.append(String.format(format, "LongitudeDegrees = ", mLongitudeDegrees));
- builder.append(String.format(format, "AltitudeMeters = ", mAltitudeMeters));
- builder.append(String.format(format, "AzimuthDegrees = ", mAzimuthDegrees));
+ StringBuilder builder = new StringBuilder("ReflectingPlane[");
+ builder.append(" LatitudeDegrees=").append(mLatitudeDegrees);
+ builder.append(" LongitudeDegrees=").append(mLongitudeDegrees);
+ builder.append(" AltitudeMeters=").append(mAltitudeMeters);
+ builder.append(" AzimuthDegrees=").append(mAzimuthDegrees);
+ builder.append(']');
return builder.toString();
}
@Override
- public void writeToParcel(@NonNull Parcel parcel, int flags) {
- parcel.writeDouble(mLatitudeDegrees);
- parcel.writeDouble(mLongitudeDegrees);
- parcel.writeDouble(mAltitudeMeters);
- parcel.writeDouble(mAzimuthDegrees);
+ public boolean equals(Object obj) {
+ if (obj instanceof GnssReflectingPlane) {
+ GnssReflectingPlane that = (GnssReflectingPlane) obj;
+ return Double.compare(this.mLatitudeDegrees, that.mLatitudeDegrees) == 0
+ && Double.compare(this.mLongitudeDegrees, that.mLongitudeDegrees) == 0
+ && Double.compare(this.mAltitudeMeters, that.mAltitudeMeters) == 0
+ && Double.compare(this.mAzimuthDegrees, that.mAzimuthDegrees) == 0;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mLatitudeDegrees, mLatitudeDegrees, mAltitudeMeters, mAzimuthDegrees);
}
/** Builder for {@link GnssReflectingPlane} */
diff --git a/location/java/android/location/GnssSingleSatCorrection.java b/location/java/android/location/GnssSingleSatCorrection.java
index 262630b79cb0..a7fce0aaaf6c 100644
--- a/location/java/android/location/GnssSingleSatCorrection.java
+++ b/location/java/android/location/GnssSingleSatCorrection.java
@@ -16,6 +16,11 @@
package android.location;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+
import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -26,6 +31,8 @@ import android.os.Parcelable;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
@@ -36,106 +43,47 @@ import java.util.Objects;
@SystemApi
public final class GnssSingleSatCorrection implements Parcelable {
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mProbSatIsLos}.
- *
- * @hide
- */
- public static final int HAS_PROB_SAT_IS_LOS_MASK = 1 << 0;
-
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mExcessPathLengthMeters}.
- *
- * @hide
- */
- public static final int HAS_EXCESS_PATH_LENGTH_MASK = 1 << 1;
-
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mExcessPathLengthUncertaintyMeters}.
- *
- * @hide
- */
- public static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK = 1 << 2;
-
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mReflectingPlane}.
- *
- * @hide
- */
- public static final int HAS_REFLECTING_PLANE_MASK = 1 << 3;
+ private static final int HAS_PROB_SAT_IS_LOS_MASK =
+ SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+ private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+ private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+ private static final int HAS_COMBINED_ATTENUATION_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
- /** A bitmask of fields present in this object (see HAS_* constants defined above) */
+ /* A bitmask of fields present in this object (see HAS_* constants defined above). */
private final int mSingleSatCorrectionFlags;
- /** Defines the constellation of the given satellite as defined in {@link GnssStatus}. */
- @GnssStatus.ConstellationType
private final int mConstellationType;
-
- /**
- * Satellite vehicle ID number
- *
- * <p>Interpretation depends on {@link GnssStatus#getSvid(int)}.
- */
- @IntRange(from = 0)
private final int mSatId;
-
- /**
- * Carrier frequency of the signal to be corrected, for example it can be the GPS center
- * frequency for L1 = 1,575,420,000 Hz, varying GLO channels, etc.
- *
- * <p>For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two correction
- * objects will be reported for this same satellite, in one of the correction objects, all the
- * values related to L1 will be filled, and in the other all of the values related to L5 will be
- * filled.
- */
- @FloatRange(from = 0.0f, fromInclusive = false)
private final float mCarrierFrequencyHz;
-
- /**
- * The probability that the satellite is estimated to be in Line-of-Sight condition at the given
- * location.
- */
- @FloatRange(from = 0.0f, to = 1.0f)
private final float mProbSatIsLos;
+ private final float mCombinedExcessPathLengthMeters;
+ private final float mCombinedExcessPathLengthUncertaintyMeters;
+ private final float mCombinedAttenuationDb;
- /**
- * Excess path length to be subtracted from pseudorange before using it in calculating location.
- */
- @FloatRange(from = 0.0f)
- private final float mExcessPathLengthMeters;
-
- /** Error estimate (1-sigma) for the Excess path length estimate */
- @FloatRange(from = 0.0f)
- private final float mExcessPathLengthUncertaintyMeters;
-
- /**
- * Defines the reflecting plane location and azimuth information
- *
- * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
- * signal goes through multiple reflections or if reflection plane serving is not supported.
- */
- @Nullable
- private final GnssReflectingPlane mReflectingPlane;
+ @NonNull
+ private final List<GnssExcessPathInfo> mGnssExcessPathInfoList;
private GnssSingleSatCorrection(int singleSatCorrectionFlags, int constellationType, int satId,
float carrierFrequencyHz, float probSatIsLos, float excessPathLengthMeters,
- float excessPathLengthUncertaintyMeters, GnssReflectingPlane reflectingPlane) {
+ float excessPathLengthUncertaintyMeters,
+ float combinedAttenuationDb,
+ @NonNull List<GnssExcessPathInfo> gnssExcessPathInfoList) {
mSingleSatCorrectionFlags = singleSatCorrectionFlags;
mConstellationType = constellationType;
mSatId = satId;
mCarrierFrequencyHz = carrierFrequencyHz;
mProbSatIsLos = probSatIsLos;
- mExcessPathLengthMeters = excessPathLengthMeters;
- mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
- mReflectingPlane = reflectingPlane;
+ mCombinedExcessPathLengthMeters = excessPathLengthMeters;
+ mCombinedExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mCombinedAttenuationDb = combinedAttenuationDb;
+ mGnssExcessPathInfoList = gnssExcessPathInfoList;
}
/**
- * Gets a bitmask of fields present in this object
+ * Gets a bitmask of fields present in this object.
*
* @hide
*/
@@ -193,29 +141,46 @@ public final class GnssSingleSatCorrection implements Parcelable {
}
/**
- * Returns the Excess path length to be subtracted from pseudorange before using it in
+ * Returns the combined excess path length to be subtracted from pseudorange before using it in
* calculating location.
*/
@FloatRange(from = 0.0f)
public float getExcessPathLengthMeters() {
- return mExcessPathLengthMeters;
+ return mCombinedExcessPathLengthMeters;
}
- /** Returns the error estimate (1-sigma) for the Excess path length estimate */
+ /** Returns the error estimate (1-sigma) for the combined excess path length estimate. */
@FloatRange(from = 0.0f)
public float getExcessPathLengthUncertaintyMeters() {
- return mExcessPathLengthUncertaintyMeters;
+ return mCombinedExcessPathLengthUncertaintyMeters;
}
/**
- * Returns the reflecting plane characteristics at which the signal has bounced
+ * Returns the combined expected reduction of signal strength for this satellite in
+ * non-negative dB.
+ */
+ @FloatRange(from = 0.0f)
+ public float getCombinedAttenuationDb() {
+ return mCombinedAttenuationDb;
+ }
+
+ /**
+ * Returns the reflecting plane characteristics at which the signal has bounced.
*
- * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
- * signal goes through multiple reflections or if reflection plane serving is not supported
+ * @deprecated Combined excess path does not have a reflecting plane.
*/
@Nullable
+ @Deprecated
public GnssReflectingPlane getReflectingPlane() {
- return mReflectingPlane;
+ return null;
+ }
+
+ /**
+ * Returns the list of {@link GnssExcessPathInfo} associated with this satellite signal.
+ */
+ @NonNull
+ public List<GnssExcessPathInfo> getGnssExcessPathInfoList() {
+ return mGnssExcessPathInfoList;
}
/** Returns {@code true} if {@link #getProbabilityLineOfSight()} is valid. */
@@ -225,17 +190,27 @@ public final class GnssSingleSatCorrection implements Parcelable {
/** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
public boolean hasExcessPathLength() {
- return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0;
}
/** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
public boolean hasExcessPathLengthUncertainty() {
- return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
}
- /** Returns {@code true} if {@link #getReflectingPlane()} is valid. */
+ /**
+ * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+ *
+ * @deprecated Combined excess path does not have a reflecting plane.
+ */
+ @Deprecated
public boolean hasReflectingPlane() {
- return (mSingleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+ return false;
+ }
+
+ /** Returns {@code true} if {@link #getCombinedAttenuationDb()} is valid. */
+ public boolean hasCombinedAttenuation() {
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0;
}
@Override
@@ -253,14 +228,15 @@ public final class GnssSingleSatCorrection implements Parcelable {
parcel.writeFloat(mProbSatIsLos);
}
if (hasExcessPathLength()) {
- parcel.writeFloat(mExcessPathLengthMeters);
+ parcel.writeFloat(mCombinedExcessPathLengthMeters);
}
if (hasExcessPathLengthUncertainty()) {
- parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+ parcel.writeFloat(mCombinedExcessPathLengthUncertaintyMeters);
}
- if (hasReflectingPlane()) {
- mReflectingPlane.writeToParcel(parcel, flags);
+ if (hasCombinedAttenuation()) {
+ parcel.writeFloat(mCombinedAttenuationDb);
}
+ parcel.writeTypedList(mGnssExcessPathInfoList);
}
public static final Creator<GnssSingleSatCorrection> CREATOR =
@@ -274,18 +250,21 @@ public final class GnssSingleSatCorrection implements Parcelable {
float carrierFrequencyHz = parcel.readFloat();
float probSatIsLos = (singleSatCorrectionFlags & HAS_PROB_SAT_IS_LOS_MASK) != 0
? parcel.readFloat() : 0;
- float excessPathLengthMeters =
- (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+ float combinedExcessPathLengthMeters =
+ (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0
? parcel.readFloat() : 0;
- float excessPathLengthUncertaintyMeters =
- (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+ float combinedExcessPathLengthUncertaintyMeters =
+ (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK)
+ != 0 ? parcel.readFloat() : 0;
+ float combinedAttenuationDb =
+ (singleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0
? parcel.readFloat() : 0;
- GnssReflectingPlane reflectingPlane =
- (singleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0
- ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+ List<GnssExcessPathInfo> gnssExcessPathInfoList = parcel.createTypedArrayList(
+ GnssExcessPathInfo.CREATOR);
return new GnssSingleSatCorrection(singleSatCorrectionFlags, constellationType,
- satId, carrierFrequencyHz, probSatIsLos, excessPathLengthMeters,
- excessPathLengthUncertaintyMeters, reflectingPlane);
+ satId, carrierFrequencyHz, probSatIsLos, combinedExcessPathLengthMeters,
+ combinedExcessPathLengthUncertaintyMeters, combinedAttenuationDb,
+ gnssExcessPathInfoList);
}
@Override
@@ -296,56 +275,24 @@ public final class GnssSingleSatCorrection implements Parcelable {
@Override
public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof GnssSingleSatCorrection)) {
- return false;
- }
-
- GnssSingleSatCorrection other = (GnssSingleSatCorrection) obj;
- if (mConstellationType != other.mConstellationType) {
- return false;
- }
- if (mSatId != other.mSatId) {
- return false;
- }
- if (Float.compare(mCarrierFrequencyHz, other.mCarrierFrequencyHz) != 0) {
- return false;
- }
-
- if (hasValidSatelliteLineOfSight() != other.hasValidSatelliteLineOfSight()) {
- return false;
- }
- if (hasValidSatelliteLineOfSight()
- && Float.compare(mProbSatIsLos, other.mProbSatIsLos) != 0) {
- return false;
- }
-
- if (hasExcessPathLength() != other.hasExcessPathLength()) {
- return false;
- }
- if (hasExcessPathLength()
- && Float.compare(mExcessPathLengthMeters, other.mExcessPathLengthMeters) != 0) {
- return false;
- }
-
- if (hasExcessPathLengthUncertainty() != other.hasExcessPathLengthUncertainty()) {
- return false;
- }
- if (hasExcessPathLengthUncertainty() && Float.compare(mExcessPathLengthUncertaintyMeters,
- other.mExcessPathLengthUncertaintyMeters) != 0) {
- return false;
- }
-
- if (hasReflectingPlane() != other.hasReflectingPlane()) {
- return false;
- }
- if (hasReflectingPlane()
- && !mReflectingPlane.equals(other.mReflectingPlane)) {
- return false;
- }
- return true;
+ if (obj instanceof GnssSingleSatCorrection) {
+ GnssSingleSatCorrection that = (GnssSingleSatCorrection) obj;
+ return this.mSingleSatCorrectionFlags == that.mSingleSatCorrectionFlags
+ && this.mConstellationType == that.mConstellationType
+ && this.mSatId == that.mSatId
+ && Float.compare(mCarrierFrequencyHz, that.mCarrierFrequencyHz) == 0
+ && (!hasValidSatelliteLineOfSight() || Float.compare(mProbSatIsLos,
+ that.mProbSatIsLos) == 0)
+ && (!hasExcessPathLength() || Float.compare(mCombinedExcessPathLengthMeters,
+ that.mCombinedExcessPathLengthMeters) == 0)
+ && (!hasExcessPathLengthUncertainty() || Float.compare(
+ mCombinedExcessPathLengthUncertaintyMeters,
+ that.mCombinedExcessPathLengthUncertaintyMeters) == 0)
+ && (!hasCombinedAttenuation() || Float.compare(mCombinedAttenuationDb,
+ that.mCombinedAttenuationDb) == 0)
+ && mGnssExcessPathInfoList.equals(that.mGnssExcessPathInfoList);
+ }
+ return false;
}
@Override
@@ -355,9 +302,10 @@ public final class GnssSingleSatCorrection implements Parcelable {
mSatId,
mCarrierFrequencyHz,
mProbSatIsLos,
- mExcessPathLengthMeters,
- mExcessPathLengthUncertaintyMeters,
- mReflectingPlane);
+ mCombinedExcessPathLengthMeters,
+ mCombinedExcessPathLengthUncertaintyMeters,
+ mCombinedAttenuationDb,
+ mGnssExcessPathInfoList);
}
@NonNull
@@ -371,14 +319,19 @@ public final class GnssSingleSatCorrection implements Parcelable {
builder.append(" ProbSatIsLos=").append(mProbSatIsLos);
}
if (hasExcessPathLength()) {
- builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+ builder.append(" CombinedExcessPathLengthMeters=").append(
+ mCombinedExcessPathLengthMeters);
}
if (hasExcessPathLengthUncertainty()) {
- builder.append(" ExcessPathLengthUncertaintyMeters=").append(
- mExcessPathLengthUncertaintyMeters);
+ builder.append(" CombinedExcessPathLengthUncertaintyMeters=").append(
+ mCombinedExcessPathLengthUncertaintyMeters);
}
- if (hasReflectingPlane()) {
- builder.append(" ReflectingPlane=").append(mReflectingPlane);
+ if (hasCombinedAttenuation()) {
+ builder.append(" CombinedAttenuationDb=").append(
+ mCombinedAttenuationDb);
+ }
+ if (!mGnssExcessPathInfoList.isEmpty()) {
+ builder.append(' ').append(mGnssExcessPathInfoList.toString());
}
builder.append(']');
return builder.toString();
@@ -386,21 +339,16 @@ public final class GnssSingleSatCorrection implements Parcelable {
/** Builder for {@link GnssSingleSatCorrection} */
public static final class Builder {
-
- /**
- * For documentation of below fields, see corresponding fields in {@link
- * GnssSingleSatCorrection}.
- */
private int mSingleSatCorrectionFlags;
-
private int mConstellationType;
private int mSatId;
private float mCarrierFrequencyHz;
private float mProbSatIsLos;
- private float mExcessPathLengthMeters;
- private float mExcessPathLengthUncertaintyMeters;
- @Nullable
- private GnssReflectingPlane mReflectingPlane;
+ private float mCombinedExcessPathLengthMeters;
+ private float mCombinedExcessPathLengthUncertaintyMeters;
+ private float mCombinedAttenuationDb;
+ @NonNull
+ private List<GnssExcessPathInfo> mGnssExcessInfoList = new ArrayList<>();
/** Sets the constellation type. */
@NonNull public Builder setConstellationType(
@@ -409,18 +357,18 @@ public final class GnssSingleSatCorrection implements Parcelable {
return this;
}
- /** Sets the Satellite ID defined in the ICD of the given constellation. */
+ /** Sets the satellite ID defined in the ICD of the given constellation. */
@NonNull public Builder setSatelliteId(@IntRange(from = 0) int satId) {
Preconditions.checkArgumentNonnegative(satId, "satId should be non-negative.");
mSatId = satId;
return this;
}
- /** Sets the Carrier frequency in Hz. */
+ /** Sets the carrier frequency in Hz. */
@NonNull public Builder setCarrierFrequencyHz(
@FloatRange(from = 0.0f, fromInclusive = false) float carrierFrequencyHz) {
- Preconditions.checkArgument(
- carrierFrequencyHz >= 0, "carrierFrequencyHz should be non-negative.");
+ Preconditions.checkArgumentInRange(
+ carrierFrequencyHz, 0, Float.MAX_VALUE, "carrierFrequencyHz");
mCarrierFrequencyHz = carrierFrequencyHz;
return this;
}
@@ -450,58 +398,90 @@ public final class GnssSingleSatCorrection implements Parcelable {
}
/**
- * Sets the Excess path length to be subtracted from pseudorange before using it in
+ * Sets the combined excess path length to be subtracted from pseudorange before using it in
* calculating location.
*/
- @NonNull public Builder setExcessPathLengthMeters(
- @FloatRange(from = 0.0f) float excessPathLengthMeters) {
- Preconditions.checkArgument(excessPathLengthMeters >= 0,
- "excessPathLengthMeters should be non-negative.");
- mExcessPathLengthMeters = excessPathLengthMeters;
- mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+ @NonNull
+ public Builder setExcessPathLengthMeters(
+ @FloatRange(from = 0.0f) float combinedExcessPathLengthMeters) {
+ Preconditions.checkArgumentInRange(combinedExcessPathLengthMeters, 0, Float.MAX_VALUE,
+ "excessPathLengthMeters");
+ mCombinedExcessPathLengthMeters = combinedExcessPathLengthMeters;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
return this;
}
/**
- * Clears the Excess path length.
+ * Clears the combined excess path length.
*
* <p>This is to negate {@link #setExcessPathLengthMeters} call.
*/
@NonNull public Builder clearExcessPathLengthMeters() {
- mExcessPathLengthMeters = 0;
- mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+ mCombinedExcessPathLengthMeters = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
return this;
}
- /** Sets the error estimate (1-sigma) for the Excess path length estimate */
+ /** Sets the error estimate (1-sigma) for the combined excess path length estimate. */
@NonNull public Builder setExcessPathLengthUncertaintyMeters(
- @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
- Preconditions.checkArgument(excessPathLengthUncertaintyMeters >= 0,
- "excessPathLengthUncertaintyMeters should be non-negative.");
- mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
- mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ @FloatRange(from = 0.0f) float combinedExcessPathLengthUncertaintyMeters) {
+ Preconditions.checkArgumentInRange(combinedExcessPathLengthUncertaintyMeters, 0,
+ Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+ mCombinedExcessPathLengthUncertaintyMeters = combinedExcessPathLengthUncertaintyMeters;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
return this;
}
/**
- * Clears the error estimate (1-sigma) for the Excess path length estimate
+ * Clears the error estimate (1-sigma) for the combined excess path length estimate.
*
* <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
*/
@NonNull public Builder clearExcessPathLengthUncertaintyMeters() {
- mExcessPathLengthUncertaintyMeters = 0;
- mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ mCombinedExcessPathLengthUncertaintyMeters = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
return this;
}
- /** Sets the reflecting plane information */
+ /**
+ * Sets the combined attenuation in Db.
+ */
+ @NonNull public Builder setCombinedAttenuationDb(
+ @FloatRange(from = 0.0f) float combinedAttenuationDb) {
+ Preconditions.checkArgumentInRange(combinedAttenuationDb, 0, Float.MAX_VALUE,
+ "combinedAttenuationDb");
+ mCombinedAttenuationDb = combinedAttenuationDb;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the combined attenuation.
+ *
+ * <p>This is to negate {@link #setCombinedAttenuationDb} call.
+ */
+ @NonNull public Builder clearCombinedAttenuationDb() {
+ mCombinedAttenuationDb = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Sets the reflecting plane information.
+ *
+ * @deprecated Combined excess path does not have a reflecting plane.
+ */
+ @Deprecated
@NonNull public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
- mReflectingPlane = reflectingPlane;
- if (reflectingPlane != null) {
- mSingleSatCorrectionFlags |= HAS_REFLECTING_PLANE_MASK;
- } else {
- mSingleSatCorrectionFlags &= ~HAS_REFLECTING_PLANE_MASK;
- }
+ return this;
+ }
+
+ /**
+ * Sets the collection of {@link GnssExcessPathInfo}.
+ */
+ @NonNull
+ public Builder setGnssExcessPathInfoList(@NonNull List<GnssExcessPathInfo> infoList) {
+ mGnssExcessInfoList = new ArrayList<>(infoList);
return this;
}
@@ -512,9 +492,10 @@ public final class GnssSingleSatCorrection implements Parcelable {
mSatId,
mCarrierFrequencyHz,
mProbSatIsLos,
- mExcessPathLengthMeters,
- mExcessPathLengthUncertaintyMeters,
- mReflectingPlane);
+ mCombinedExcessPathLengthMeters,
+ mCombinedExcessPathLengthUncertaintyMeters,
+ mCombinedAttenuationDb,
+ mGnssExcessInfoList);
}
}
}
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/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 4956dbefa240..7d3f91653cea 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -793,8 +793,11 @@ public final class MediaFormat {
* By default, the decoder will output the same number of channels as present in the encoded
* stream, if supported. Set this value to limit the number of output channels, and use
* the downmix information in the stream, if available.
- * <p>Values larger than the number of channels in the content to decode are ignored.
+ * <p>Values larger than the number of channels in the content to decode behave just
+ * like the actual channel count of the content (e.g. passing 99 for the decoding of 5.1 content
+ * will behave like using 6).
* <p>This key is only used during decoding.
+ * @deprecated Use the non-AAC-specific key {@link #KEY_MAX_OUTPUT_CHANNEL_COUNT} instead
*/
public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
index 8811e16b3317..74ca4b858ff6 100644
--- a/media/java/android/media/Spatializer.java
+++ b/media/java/android/media/Spatializer.java
@@ -882,8 +882,12 @@ public class Spatializer {
/**
* @hide
- * Returns the id of the output stream used for the spatializer effect playback
+ * Returns the id of the output stream used for the spatializer effect playback.
+ * This getter or associated listener {@link OnSpatializerOutputChangedListener} can be used for
+ * handling spatializer output-specific configurations (e.g. disabling speaker post-processing
+ * to avoid double-processing of the spatialized path).
* @return id of the output stream, or 0 if no spatializer playback is active
+ * @see #setOnSpatializerOutputChangedListener(Executor, OnSpatializerOutputChangedListener)
*/
@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
@RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
@@ -920,6 +924,8 @@ public class Spatializer {
mOutputDispatcher = new SpatializerOutputDispatcherStub();
try {
mAm.getService().registerSpatializerOutputCallback(mOutputDispatcher);
+ // immediately report the current output
+ mOutputDispatcher.dispatchSpatializerOutputChanged(getOutput());
} catch (RemoteException e) {
mOutputListener = null;
mOutputDispatcher = null;
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 19fc0521d7aa..b136d5bc4db3 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -17,6 +17,7 @@
package android.media.projection;
import android.media.projection.IMediaProjectionCallback;
+import android.window.WindowContainerToken;
/** {@hide} */
interface IMediaProjection {
@@ -28,4 +29,16 @@ interface IMediaProjection {
int applyVirtualDisplayFlags(int flags);
void registerCallback(IMediaProjectionCallback callback);
void unregisterCallback(IMediaProjectionCallback callback);
+
+ /**
+ * Returns the {@link android.window.WindowContainerToken} identifying the task to record, or
+ * {@code null} if there is none.
+ */
+ WindowContainerToken getTaskRecordingWindowContainerToken();
+
+ /**
+ * Updates the {@link android.window.WindowContainerToken} identifying the task to record, or
+ * {@code null} if there is none.
+ */
+ void setTaskRecordingWindowContainerToken(in WindowContainerToken token);
}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 4dde5e8d39a2..b5f95938f845 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -25,13 +25,14 @@ import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
import android.view.ContentRecordingSession;
+import android.view.IWindowManager;
import android.view.Surface;
import android.view.WindowManagerGlobal;
+import android.window.WindowContainerToken;
import java.util.Map;
@@ -171,16 +172,34 @@ public final class MediaProjection {
@NonNull VirtualDisplayConfig.Builder virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
try {
- final Context windowContext = mContext.createWindowContext(
- mContext.getDisplayNoVerify(),
- TYPE_APPLICATION, null /* options */);
- final IBinder windowContextToken = windowContext.getWindowContextToken();
+ final IWindowManager wmService = WindowManagerGlobal.getWindowManagerService();
+ final WindowContainerToken taskWindowContainerToken =
+ mImpl.getTaskRecordingWindowContainerToken();
+ Context windowContext = null;
+ ContentRecordingSession session;
+ if (taskWindowContainerToken == null) {
+ windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+ TYPE_APPLICATION, null /* options */);
+ session = ContentRecordingSession.createDisplaySession(
+ windowContext.getWindowContextToken());
+ } else {
+ session = ContentRecordingSession.createTaskSession(
+ taskWindowContainerToken.asBinder());
+ }
virtualDisplayConfig.setWindowManagerMirroring(true);
final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this,
- virtualDisplayConfig.build(),
- callback, handler, windowContext);
- setSession(windowContextToken, virtualDisplay);
+ virtualDisplayConfig.build(), callback, handler, windowContext);
+ if (virtualDisplay == null) {
+ // Since WM handling a new display and DM creating a new VirtualDisplay is async,
+ // WM may have tried to start task recording and encountered an error that required
+ // stopping recording entirely. The VirtualDisplay would then be null when the
+ // MediaProjection is no longer active.
+ return null;
+ }
+ session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
+ // Successfully set up, so save the current session details.
+ wmService.setContentRecordingSession(session);
return virtualDisplay;
} catch (RemoteException e) {
// Can not capture if WMS is not accessible, so bail out.
@@ -189,28 +208,6 @@ public final class MediaProjection {
}
/**
- * Updates the {@link ContentRecordingSession} describing the recording taking place on this
- * {@link VirtualDisplay}.
- *
- * @throws RemoteException if updating the session on the server failed.
- */
- private void setSession(@NonNull IBinder windowContextToken,
- @Nullable VirtualDisplay virtualDisplay)
- throws RemoteException {
- if (virtualDisplay == null) {
- // Not able to set up a new VirtualDisplay.
- return;
- }
- // Identify the VirtualDisplay that will be hosting the recording.
- ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
- windowContextToken);
- session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
- // TODO(b/216625226) handle task recording.
- // Successfully set up, so save the current session details.
- WindowManagerGlobal.getWindowManagerService().setContentRecordingSession(session);
- }
-
- /**
* Stops projection.
*/
public void 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/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index a3e58d16f655..c8c6f66aa0ed 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -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..eb012721445c 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -50,6 +50,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/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
index c449d2475428..c784b09e87fc 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
@@ -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..f74b2bac957b 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -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..702832ccb3ca 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -28,9 +28,9 @@ 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.media.tv.interactive.TvInteractiveAppServiceInfo.InteractiveAppType;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -249,7 +249,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 +285,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 +488,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);
@@ -753,8 +776,16 @@ public final class TvInteractiveAppManager {
/**
* Prepares TV Interactive App service environment for the given type.
+ *
+ * <p>This method brings up the corresponding {@link TvInteractiveAppService} and prepare needed
+ * resources. It's used to set up the resources in advance, or handle non-session operations.
+ *
+ * @param tvIAppServiceId The ID of TV interactive service to prepare the resources. The
+ * ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
+ *
+ * @see TvInteractiveAppService.Session
*/
- public void prepare(@NonNull String tvIAppServiceId, int type) {
+ public void prepare(@NonNull String tvIAppServiceId, @InteractiveAppType int type) {
try {
mService.prepare(tvIAppServiceId, type, mUserId);
} catch (RemoteException e) {
@@ -767,7 +798,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 registered.
*/
public void registerAppLinkInfo(
@@ -784,7 +815,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 +831,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 +1055,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 +1700,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 +1846,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..15144f82e52c 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -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;
@@ -373,6 +374,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() {
@@ -435,6 +445,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 +464,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 +507,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 +900,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
@@ -945,6 +1009,10 @@ public abstract class TvInteractiveAppService extends Service {
onCurrentTvInputId(inputId);
}
+ void sendSigningResult(String signingId, byte[] result) {
+ onSigningResult(signingId, result);
+ }
+
void release() {
onRelease();
if (mSurface != null) {
@@ -1413,6 +1481,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/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 212051120e77..9154de008d7a 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -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,28 @@ 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";
+
private final TvInteractiveAppManager mTvInteractiveAppManager;
private final Handler mHandler = new Handler();
private final Object mCallbackLock = new Object();
@@ -242,7 +265,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 +393,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 +428,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 +475,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 +516,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 +556,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) {
@@ -725,6 +789,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 +1111,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/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
index 43f4c40f2d27..1691942c3675 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
@@ -33,17 +33,20 @@ import java.util.Objects;
*/
@SystemApi
public final class EthernetNetworkUpdateRequest implements Parcelable {
- @NonNull
+ @Nullable
private final IpConfiguration mIpConfig;
@Nullable
private final NetworkCapabilities mNetworkCapabilities;
/**
- * @return the new {@link IpConfiguration}.
+ * Setting the {@link IpConfiguration} is optional in {@link EthernetNetworkUpdateRequest}.
+ * When set to null, the existing IpConfiguration is not updated.
+ *
+ * @return the new {@link IpConfiguration} or null.
*/
- @NonNull
+ @Nullable
public IpConfiguration getIpConfiguration() {
- return new IpConfiguration(mIpConfig);
+ return mIpConfig == null ? null : new IpConfiguration(mIpConfig);
}
/**
@@ -57,9 +60,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities);
}
- private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig,
+ private EthernetNetworkUpdateRequest(@Nullable final IpConfiguration ipConfig,
@Nullable final NetworkCapabilities networkCapabilities) {
- Objects.requireNonNull(ipConfig);
mIpConfig = ipConfig;
mNetworkCapabilities = networkCapabilities;
}
@@ -90,7 +92,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
*/
public Builder(@NonNull final EthernetNetworkUpdateRequest request) {
Objects.requireNonNull(request);
- mBuilderIpConfig = new IpConfiguration(request.mIpConfig);
+ mBuilderIpConfig = null == request.mIpConfig
+ ? null : new IpConfiguration(request.mIpConfig);
mBuilderNetworkCapabilities = null == request.mNetworkCapabilities
? null : new NetworkCapabilities(request.mNetworkCapabilities);
}
@@ -101,8 +104,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
* @return The builder to facilitate chaining.
*/
@NonNull
- public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) {
- mBuilderIpConfig = new IpConfiguration(ipConfig);
+ public Builder setIpConfiguration(@Nullable final IpConfiguration ipConfig) {
+ mBuilderIpConfig = ipConfig == null ? null : new IpConfiguration(ipConfig);
return this;
}
@@ -119,9 +122,16 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
/**
* Build {@link EthernetNetworkUpdateRequest} return the current update request.
+ *
+ * @throws IllegalStateException when both mBuilderNetworkCapabilities and mBuilderIpConfig
+ * are null.
*/
@NonNull
public EthernetNetworkUpdateRequest build() {
+ if (mBuilderIpConfig == null && mBuilderNetworkCapabilities == null) {
+ throw new IllegalStateException(
+ "Cannot construct an empty EthernetNetworkUpdateRequest");
+ }
return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities);
}
}
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/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
new file mode 100644
index 000000000000..221d2db00031
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:alpha="?android:attr/disabledAlpha"
+ android:color="@color/settingslib_text_color_primary_device_default"/>
+ <item android:color="@color/settingslib_text_color_primary_device_default"/>
+</selector>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 9d3991119338..cba1a9cf0003 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -17,7 +17,7 @@
<resources>
<style name="TextAppearance.PreferenceTitle.SettingsLib"
parent="@android:style/TextAppearance.Material.Subhead">
- <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
+ <item name="android:textColor">@color/settingslib_text_color_primary</item>
<item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20sp</item>
</style>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 579e3d7a6d39..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>
@@ -1582,4 +1565,11 @@
<string name="keyboard_layout_dialog_title">Choose keyboard layout</string>
<!-- Label of the default keyboard layout. [CHAR LIMIT=35] -->
<string name="keyboard_layout_default_label">Default</string>
+
+ <!-- Special access > Title for managing turn screen on settings. [CHAR LIMIT=50] -->
+ <string name="turn_screen_on_title">Turn screen on</string>
+ <!-- Label for a setting which controls whether an app can turn the screen on [CHAR LIMIT=45] -->
+ <string name="allow_turn_screen_on">Allow turning the screen on</string>
+ <!-- Description for a setting which controls whether an app can turn the screen on [CHAR LIMIT=NONE] -->
+ <string name="allow_turn_screen_on_description">Allow an app to turn the screen on. If granted, the app may turn on the screen at any time without your explicit intent.</string>
</resources>
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/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 7f300cafaa08..2a28891e9158 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -753,7 +753,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
ParcelUuid[] uuids = mDevice.getUuids();
if (uuids == null) return false;
- ParcelUuid[] localUuids = mLocalAdapter.getUuids();
+ List<ParcelUuid> uuidsList = mLocalAdapter.getUuidsList();
+ ParcelUuid[] localUuids = new ParcelUuid[uuidsList.size()];
+ uuidsList.toArray(localUuids);
+
if (localUuids == null) return false;
/*
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index e7a6b327bacd..31cc6a4ba412 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -126,7 +126,10 @@ public class LocalBluetoothAdapter {
}
public ParcelUuid[] getUuids() {
- return mAdapter.getUuids();
+ List<ParcelUuid> uuidsList = mAdapter.getUuidsList();
+ ParcelUuid[] uuidsArray = new ParcelUuid[uuidsList.size()];
+ uuidsList.toArray(uuidsArray);
+ return uuidsArray;
}
public boolean isDiscovering() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
index 0cb2c0b22a4c..63a9f0c5c7f4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
@@ -78,6 +78,11 @@ class AvatarPhotoController {
static final int REQUEST_CODE_TAKE_PHOTO = 1002;
static final int REQUEST_CODE_CROP_PHOTO = 1003;
+ /**
+ * Delay to allow the photo picker exit animation to complete before the crop activity opens.
+ */
+ private static final long DELAY_BEFORE_CROP_MILLIS = 150;
+
private static final String IMAGES_DIR = "multi_user";
private static final String PRE_CROP_PICTURE_FILE_NAME = "PreCropEditUserPhoto.jpg";
private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
@@ -131,13 +136,15 @@ class AvatarPhotoController {
mAvatarUi.returnUriResult(pictureUri);
return true;
case REQUEST_CODE_TAKE_PHOTO:
- case REQUEST_CODE_CHOOSE_PHOTO:
if (mTakePictureUri.equals(pictureUri)) {
cropPhoto(pictureUri);
} else {
- copyAndCropPhoto(pictureUri);
+ copyAndCropPhoto(pictureUri, false);
}
return true;
+ case REQUEST_CODE_CHOOSE_PHOTO:
+ copyAndCropPhoto(pictureUri, true);
+ return true;
}
return false;
}
@@ -154,7 +161,7 @@ class AvatarPhotoController {
mAvatarUi.startActivityForResult(intent, REQUEST_CODE_CHOOSE_PHOTO);
}
- private void copyAndCropPhoto(final Uri pictureUri) {
+ private void copyAndCropPhoto(final Uri pictureUri, boolean delayBeforeCrop) {
try {
ThreadUtils.postOnBackgroundThread(() -> {
final ContentResolver cr = mContextInjector.getContentResolver();
@@ -165,11 +172,17 @@ class AvatarPhotoController {
Log.w(TAG, "Failed to copy photo", e);
return;
}
- ThreadUtils.postOnMainThread(() -> {
+ Runnable cropRunnable = () -> {
if (!mAvatarUi.isFinishing()) {
cropPhoto(mPreCropPictureUri);
}
- });
+ };
+ if (delayBeforeCrop) {
+ ThreadUtils.postOnMainThreadDelayed(cropRunnable, DELAY_BEFORE_CROP_MILLIS);
+ } else {
+ ThreadUtils.postOnMainThread(cropRunnable);
+ }
+
}).get();
} catch (InterruptedException | ExecutionException e) {
Log.e(TAG, "Error performing copy-and-crop", e);
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
index 69f1c17f97b1..2c1d5da5e941 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
@@ -84,6 +84,13 @@ public class ThreadUtils {
getUiThreadHandler().post(runnable);
}
+ /**
+ * Posts the runnable on the main thread with a delay.
+ */
+ public static void postOnMainThreadDelayed(Runnable runnable, long delayMillis) {
+ getUiThreadHandler().postDelayed(runnable, delayMillis);
+ }
+
private static synchronized ExecutorService getThreadExecutor() {
if (sThreadExecutor == null) {
sThreadExecutor = Executors.newFixedThreadPool(
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/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 02a4070415dd..740697ba98af 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -54,6 +54,14 @@
the shade (in alpha) -->
<dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
+ <!-- The notifications scrim transition should start when the other scrims' transition is at
+ 95%. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_delay">76dp</dimen>
+
+ <!-- The notifications scrim transition duration is 66.6% of the duration of the other scrims'
+ transition. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_distance">53.28dp</dimen>
+
<!-- Distance that the full shade transition takes in order for the keyguard content on
NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
<dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">80dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f73010e2a39a..6871310ebd6b 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1141,6 +1141,12 @@
the shade (in alpha) -->
<dimen name="lockscreen_shade_scrim_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+ <!-- Distance that it takes in order for the notifications scrim fade in to start. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_delay">0dp</dimen>
+
+ <!-- Distance that it takes for the notifications scrim to fully fade if after it started. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_distance">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+
<!-- Distance that the full shade transition takes in order for the keyguard content on
NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
<dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index a27b9cd357f4..b811c51c952b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -116,7 +116,7 @@ class AuthRippleController @Inject constructor(
}
fun showRipple(biometricSourceType: BiometricSourceType?) {
- if (!keyguardUpdateMonitor.isKeyguardVisible ||
+ if (!(keyguardUpdateMonitor.isKeyguardVisible || keyguardUpdateMonitor.isDreaming) ||
keyguardUpdateMonitor.userNeedsStrongAuth()) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 7a4dee294dd6..d472aeee1073 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -812,7 +812,7 @@ class MediaHierarchyManager @Inject constructor(
@TransformationType
fun calculateTransformationType(): Int {
if (isTransitioningToFullShade) {
- if (inSplitShade) {
+ if (inSplitShade && areGuidedTransitionHostsVisible()) {
return TRANSFORMATION_TYPE_TRANSITION
}
return TRANSFORMATION_TYPE_FADE
@@ -829,6 +829,11 @@ class MediaHierarchyManager @Inject constructor(
return TRANSFORMATION_TYPE_TRANSITION
}
+ private fun areGuidedTransitionHostsVisible(): Boolean {
+ return getHost(previousLocation)?.visible == true &&
+ getHost(desiredLocation)?.visible == true
+ }
+
/**
* @return the current transformation progress if we're in a guided transformation and -1
* otherwise
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/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index ab4d0dd355f3..de3e89d6dc8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -116,6 +116,16 @@ class LockscreenShadeTransitionController @Inject constructor(
private var scrimTransitionDistance = 0
/**
+ * Distance that it takes in order for the notifications scrim fade in to start.
+ */
+ private var notificationsScrimTransitionDelay = 0
+
+ /**
+ * Distance that it takes for the notifications scrim to fully fade if after it started.
+ */
+ private var notificationsScrimTransitionDistance = 0
+
+ /**
* Distance that the full shade transition takes in order for the notification shelf to fully
* expand.
*/
@@ -225,6 +235,10 @@ class LockscreenShadeTransitionController @Inject constructor(
R.dimen.lockscreen_shade_transition_by_tap_distance)
scrimTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_scrim_transition_distance)
+ notificationsScrimTransitionDelay = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay)
+ notificationsScrimTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance)
notificationShelfTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_notif_shelf_transition_distance)
qsTransitionDistance = context.resources.getDimensionPixelSize(
@@ -405,6 +419,7 @@ class LockscreenShadeTransitionController @Inject constructor(
false /* animate */, 0 /* delay */)
mediaHierarchyManager.setTransitionToFullShadeAmount(field)
+ transitionToShadeAmountScrim(field)
transitionToShadeAmountCommon(field)
transitionToShadeAmountKeyguard(field)
}
@@ -417,10 +432,15 @@ class LockscreenShadeTransitionController @Inject constructor(
var qSDragProgress = 0f
private set
- private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
+ private fun transitionToShadeAmountScrim(dragDownAmount: Float) {
val scrimProgress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
- scrimController.setTransitionToFullShadeProgress(scrimProgress)
+ val notificationsScrimDragAmount = dragDownAmount - notificationsScrimTransitionDelay
+ val notificationsScrimProgress = MathUtils.saturate(
+ notificationsScrimDragAmount / notificationsScrimTransitionDistance)
+ scrimController.setTransitionToFullShadeProgress(scrimProgress, notificationsScrimProgress)
+ }
+ private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
if (depthControllerTransitionDistance > 0) {
val depthProgress =
MathUtils.saturate(dragDownAmount / depthControllerTransitionDistance)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 7fbb0f1182c0..02aa1f2fd585 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -25,7 +25,7 @@ class NotificationLaunchAnimatorControllerProvider @Inject constructor(
@JvmOverloads
fun getAnimatorController(
notification: ExpandableNotificationRow,
- onFinishAnimationCallback: Runnable = Runnable {}
+ onFinishAnimationCallback: Runnable? = null
): NotificationLaunchAnimatorController {
return NotificationLaunchAnimatorController(
notificationShadeWindowViewController,
@@ -49,7 +49,7 @@ class NotificationLaunchAnimatorController(
private val headsUpManager: HeadsUpManagerPhone,
private val notification: ExpandableNotificationRow,
private val jankMonitor: InteractionJankMonitor,
- private val onFinishAnimationCallback: Runnable
+ private val onFinishAnimationCallback: Runnable?
) : ActivityLaunchAnimator.Controller {
companion object {
@@ -123,7 +123,7 @@ class NotificationLaunchAnimatorController(
if (!willAnimate) {
removeHun(animate = true)
- onFinishAnimationCallback.run()
+ onFinishAnimationCallback?.run()
}
}
@@ -142,7 +142,7 @@ class NotificationLaunchAnimatorController(
notificationShadeWindowViewController.setExpandAnimationRunning(false)
notificationEntry.isExpandAnimationRunning = false
removeHun(animate = true)
- onFinishAnimationCallback.run()
+ onFinishAnimationCallback?.run()
}
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -162,7 +162,7 @@ class NotificationLaunchAnimatorController(
notificationListContainer.setExpandingNotification(null)
applyParams(null)
removeHun(animate = false)
- onFinishAnimationCallback.run()
+ onFinishAnimationCallback?.run()
}
private fun applyParams(params: ExpandAnimationParameters?) {
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/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 419661b766d6..1ad365bf6d7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -116,6 +116,15 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private float mTransitionToFullShadeProgress;
/**
+ * Same as {@link #mTransitionToFullShadeProgress}, but specifically for the notifications scrim
+ * on the lock screen.
+ *
+ * On split shade lock screen we want the different scrims to fade in at different times and
+ * rates.
+ */
+ private float mTransitionToLockScreenFullShadeNotificationsProgress;
+
+ /**
* If we're currently transitioning to the full shade.
*/
private boolean mTransitioningToFullShade;
@@ -574,11 +583,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
* Set the amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
* shade.
+ *
+ * @param progress the progress for all scrims.
+ * @param lockScreenNotificationsProgress the progress specifically for the notifications scrim.
*/
- public void setTransitionToFullShadeProgress(float progress) {
- if (progress != mTransitionToFullShadeProgress) {
+ public void setTransitionToFullShadeProgress(float progress,
+ float lockScreenNotificationsProgress) {
+ if (progress != mTransitionToFullShadeProgress || lockScreenNotificationsProgress
+ != mTransitionToLockScreenFullShadeNotificationsProgress) {
mTransitionToFullShadeProgress = progress;
- setTransitionToFullShade(progress > 0.0f);
+ mTransitionToLockScreenFullShadeNotificationsProgress = lockScreenNotificationsProgress;
+ setTransitionToFullShade(progress > 0.0f || lockScreenNotificationsProgress > 0.0f);
applyAndDispatchState();
}
}
@@ -754,12 +769,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
} else {
mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
}
- if (mState == ScrimState.KEYGUARD && mTransitionToFullShadeProgress > 0.0f) {
+ if (mState == ScrimState.KEYGUARD
+ && mTransitionToLockScreenFullShadeNotificationsProgress > 0.0f) {
// Interpolate the notification alpha when transitioning!
mNotificationsAlpha = MathUtils.lerp(
mNotificationsAlpha,
getInterpolatedFraction(),
- mTransitionToFullShadeProgress);
+ mTransitionToLockScreenFullShadeNotificationsProgress);
}
mNotificationsTint = mState.getNotifTint();
mBehindTint = behindTint;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 637e4bee8948..6fe92fafc075 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -397,15 +397,25 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
mMainThreadHandler.post(() -> {
final Runnable removeNotification = () -> {
mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK, summaryToRemove);
+ if (!animate) {
+ // If we're animating, this would be invoked after the activity launch
+ // animation completes. Since we're not animating, the launch already
+ // happened synchronously, so we notify the launch is complete here after
+ // onDismiss.
+ mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
+ }
};
if (mPresenter.isCollapsing()) {
- // To avoid lags we're only performing the remove
- // after the shade is collapsed
+ // To avoid lags we're only performing the remove after the shade is collapsed
mShadeController.addPostCollapseAction(removeNotification);
} else {
removeNotification.run();
}
});
+ } else if (!canBubble && !animate) {
+ // Not animating, this is the end of the launch flow (see above comment for more info).
+ mMainThreadHandler.post(
+ () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
}
mIsCollapsingToShowActivityOverLockscreen = false;
@@ -481,8 +491,9 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
boolean isActivityIntent) {
mLogger.logStartNotificationIntent(entry.getKey(), intent);
try {
- Runnable onFinishAnimationCallback =
- () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
+ Runnable onFinishAnimationCallback = animate
+ ? () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry)
+ : null;
ActivityLaunchAnimator.Controller animationController =
new StatusBarLaunchAnimatorController(
mNotificationAnimationProvider
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 7a0db1fd975c..8c7927782d2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -208,6 +208,11 @@ public abstract class SysuiTestCase {
}
}
+ /** Delegates to {@link android.testing.TestableResources#addOverride(int, Object)}. */
+ protected void overrideResource(int resourceId, Object value) {
+ mContext.getOrCreateTestableResources().addOverride(resourceId, value);
+ }
+
public static final class EmptyRunnable implements Runnable {
public void run() {
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index ec2c1de49b4c..a95da6295350 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -114,12 +114,13 @@ class AuthRippleControllerTest : SysuiTestCase() {
}
@Test
- fun testFingerprintTrigger_Ripple() {
+ fun testFingerprintTrigger_KeyguardVisible_Ripple() {
// GIVEN fp exists, keyguard is visible, user doesn't need strong auth
val fpsLocation = PointF(5f, 5f)
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
`when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
`when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
// WHEN fingerprint authenticated
@@ -136,7 +137,30 @@ class AuthRippleControllerTest : SysuiTestCase() {
}
@Test
- fun testFingerprintTrigger_KeyguardNotVisible_NoRipple() {
+ fun testFingerprintTrigger_Dreaming_Ripple() {
+ // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
+ val fpsLocation = PointF(5f, 5f)
+ `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
+ controller.onViewAttached()
+ `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(true)
+ `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
+
+ // WHEN fingerprint authenticated
+ val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+ verify(keyguardUpdateMonitor).registerCallback(captor.capture())
+ captor.value.onBiometricAuthenticated(
+ 0 /* userId */,
+ BiometricSourceType.FINGERPRINT /* type */,
+ false /* isStrongBiometric */)
+
+ // THEN update sensor location and show ripple
+ verify(rippleView).setFingerprintSensorLocation(fpsLocation, -1f)
+ verify(rippleView).startUnlockedRipple(any())
+ }
+
+ @Test
+ fun testFingerprintTrigger_KeyguardNotVisible_NotDreaming_NoRipple() {
// GIVEN fp exists & user doesn't need strong auth
val fpsLocation = PointF(5f, 5f)
`when`(authController.udfpsSensorLocation).thenReturn(fpsLocation)
@@ -145,6 +169,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
// WHEN keyguard is NOT visible & fingerprint authenticated
`when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
captor.value.onBiometricAuthenticated(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 8e201b5a3e87..203eb47165e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -223,6 +223,18 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
}
@Test
+ fun calculateTransformationType_onLockSplitShade_goingToFullShade_mediaInvisible_returnsFade() {
+ enableSplitShade()
+ goToLockscreen()
+ expandQS()
+ whenever(lockHost.visible).thenReturn(false)
+ mediaHiearchyManager.setTransitionToFullShadeAmount(10000f)
+
+ val transformType = mediaHiearchyManager.calculateTransformationType()
+ assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ }
+
+ @Test
fun calculateTransformationType_onLockShade_inSplitShade_notExpanding_returnsFade() {
enableSplitShade()
goToLockscreen()
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/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 64a0a2342a44..1d2a0ca3777a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.statusbar
+import org.mockito.Mockito.`when` as whenever
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -18,11 +19,11 @@ import com.android.systemui.statusbar.notification.row.NotificationTestHelper
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
import com.android.systemui.statusbar.phone.NotificationPanelViewController
import com.android.systemui.statusbar.phone.ScrimController
-import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.policy.FakeConfigurationController
import org.junit.After
import org.junit.Assert.assertFalse
@@ -37,14 +38,13 @@ import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
-import org.mockito.Mockito.`when` as whenever
-import org.mockito.ArgumentMatchers.eq
private fun <T> anyObject(): T {
return Mockito.anyObject<T>()
@@ -231,7 +231,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
transitionController.dragDownAmount = 10f
verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
verify(mediaHierarchyManager, never()).setTransitionToFullShadeAmount(anyFloat())
- verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat())
+ verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
@@ -242,7 +242,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
transitionController.dragDownAmount = 10f
verify(nsslController).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
verify(mediaHierarchyManager).setTransitionToFullShadeAmount(anyFloat())
- verify(scrimController).setTransitionToFullShadeProgress(anyFloat())
+ verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
@@ -311,6 +311,75 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
}
@Test
+ fun setDragAmount_setsScrimProgressBasedOnScrimDistance() {
+ val distance = 10
+ context.orCreateTestableResources
+ .addOverride(R.dimen.lockscreen_shade_scrim_transition_distance, distance)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 5f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = eq(0.5f),
+ lockScreenNotificationsProgress = anyFloat()
+ )
+ }
+
+ @Test
+ fun setDragAmount_setsNotificationsScrimProgressBasedOnNotificationsScrimDistanceAndDelay() {
+ val distance = 100
+ val delay = 10
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 20f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(0.1f)
+ )
+ }
+
+ @Test
+ fun setDragAmount_dragAmountLessThanNotifDelayDistance_setsNotificationsScrimProgressToZero() {
+ val distance = 100
+ val delay = 50
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 20f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(0f)
+ )
+ }
+
+ @Test
+ fun setDragAmount_dragAmountMoreThanTotalDistance_setsNotificationsScrimProgressToOne() {
+ val distance = 100
+ val delay = 50
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 999999f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(1f)
+ )
+ }
+
+ @Test
fun setDragDownAmount_inSplitShade_setsValueOnMediaHierarchyManager() {
enableSplitShade()
@@ -328,9 +397,21 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
}
private fun setSplitShadeEnabled(enabled: Boolean) {
- context.getOrCreateTestableResources().addOverride(
- R.bool.config_use_split_notification_shade, enabled
- )
+ overrideResource(R.bool.config_use_split_notification_shade, enabled)
configurationController.notifyConfigurationChanged()
}
+
+ /**
+ * Wrapper around [ScrimController.transitionToFullShadeProgress] that has named parameters for
+ * clarify and easier refactoring of parameter names.
+ */
+ private fun ScrimController.transitionToFullShadeProgress(
+ progress: Float,
+ lockScreenNotificationsProgress: Float
+ ) {
+ scrimController.setTransitionToFullShadeProgress(
+ progress,
+ lockScreenNotificationsProgress
+ )
+ }
}
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/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
index 83eabb667997..6526fabefe49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
@@ -6,7 +6,6 @@ import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowManagerPolicyConstants
-import androidx.annotation.AnyRes
import androidx.annotation.IdRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
@@ -104,10 +103,6 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
windowInsetsCallback = windowInsetsCallbackCaptor.value
}
- private fun overrideResource(@AnyRes id: Int, value: Any) {
- mContext.orCreateTestableResources.addOverride(id, value)
- }
-
@Test
fun testTaskbarVisibleInSplitShade() {
enableSplitShade()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 0b25467d20d8..786a8586ea39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.statusbar.phone.ScrimController.KEYGUARD_SCRIM_ALPHA;
import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;
import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT;
@@ -1263,19 +1262,36 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimController.setClipsQsScrim(true);
float progress = 0.5f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ float lsNotifProgress = 0.3f;
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
progress = 0.0f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
progress = 1.0f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
}
+ @Test
+ public void notificationTransparency_followsNotificationScrimProgress() {
+ mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
+ finishAnimationsImmediately();
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
+ finishAnimationsImmediately();
+
+ float progress = 0.5f;
+ float notifProgress = 0.3f;
+ mScrimController.setTransitionToFullShadeProgress(progress, notifProgress);
+
+ assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(notifProgress);
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index d48ce8c6803e..fa867e2796f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -447,4 +447,15 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
controllerCaptor.getValue().onIntentStarted(false);
verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
}
+
+ @Test
+ public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse_noAnimate() {
+ NotifActivityLaunchEvents.Listener listener =
+ mock(NotifActivityLaunchEvents.Listener.class);
+ mLaunchEventsEmitter.registerListener(listener);
+ when(mCentralSurfaces.shouldAnimateLaunch(anyBoolean())).thenReturn(false);
+ mNotificationActivityStarter
+ .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+ verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
+ }
}
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/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/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 1131fa8a32b8..4fdc88d3fd64 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -561,8 +561,18 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
// We were asked to fetch Bluetooth data.
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
- bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
- adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+ SynchronousResultReceiver resultReceiver =
+ new SynchronousResultReceiver("bluetooth");
+ adapter.requestControllerActivityEnergyInfo(
+ Runnable::run,
+ info -> {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY,
+ info);
+ resultReceiver.send(0, bundle);
+ }
+ );
+ bluetoothReceiver = resultReceiver;
}
}
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/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 4a853e18b3a4..f0f04e27b7de 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -139,6 +139,7 @@ public class SpatializerHelper {
private @Nullable SpatializerCallback mSpatCallback;
private @Nullable SpatializerHeadTrackingCallback mSpatHeadTrackingCallback;
private @Nullable HelperDynamicSensorCallback mDynSensorCallback;
+ private boolean mIsHeadTrackingSupported = false;
// default attributes and format that determine basic availability of spatialization
private static final AudioAttributes DEFAULT_ATTRIBUTES = new AudioAttributes.Builder()
@@ -813,8 +814,9 @@ public class SpatializerHelper {
mSpat = AudioSystem.getSpatializer(mSpatCallback);
try {
mSpat.setLevel((byte) Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL);
+ mIsHeadTrackingSupported = mSpat.isHeadTrackingSupported();
//TODO: register heatracking callback only when sensors are registered
- if (mSpat.isHeadTrackingSupported()) {
+ if (mIsHeadTrackingSupported) {
mSpat.registerHeadTrackingCallback(mSpatHeadTrackingCallback);
}
} catch (RemoteException e) {
@@ -832,12 +834,15 @@ public class SpatializerHelper {
if (mSpat != null) {
mSpatCallback = null;
try {
- mSpat.registerHeadTrackingCallback(null);
+ if (mIsHeadTrackingSupported) {
+ mSpat.registerHeadTrackingCallback(null);
+ }
mHeadTrackerAvailable = false;
mSpat.release();
} catch (RemoteException e) {
Log.e(TAG, "Can't set release spatializer cleanly", e);
}
+ mIsHeadTrackingSupported = false;
mSpat = null;
}
}
@@ -1124,7 +1129,7 @@ public class SpatializerHelper {
}
break;
}
- return true;
+ return mIsHeadTrackingSupported;
}
private void dispatchActualHeadTrackingMode(int newMode) {
@@ -1314,13 +1319,8 @@ public class SpatializerHelper {
Log.e(TAG, "not " + action + " sensors, null spatializer");
return;
}
- try {
- if (!mSpat.isHeadTrackingSupported()) {
- Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
- return;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "not " + action + " sensors, error querying headtracking", e);
+ if (!mIsHeadTrackingSupported) {
+ Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
return;
}
int headHandle = -1;
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 7cb29215b5bf..cb04ddfd636d 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -156,9 +156,15 @@ final class ColorFade {
mMode = mode;
+ DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+ if (displayInfo == null) {
+ // displayInfo can be null if the associated display has been removed. There
+ // is a delay between the display being removed and ColorFade being dismissed.
+ return false;
+ }
+
// Get the display size and layer stack.
// This is not expected to change while the color fade surface is showing.
- DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
mDisplayLayerStack = displayInfo.layerStack;
mDisplayWidth = displayInfo.getNaturalWidth();
mDisplayHeight = displayInfo.getNaturalHeight();
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 7a0cf4b592e7..540ae8165dbd 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -73,6 +73,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private final SurfaceControlProxy mSurfaceControlProxy;
+ private final boolean mIsBootDisplayModeSupported;
+
// Called with SyncRoot lock held.
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
@@ -85,6 +87,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
super(syncRoot, context, handler, listener, TAG);
mInjector = injector;
mSurfaceControlProxy = mInjector.getSurfaceControlProxy();
+ mIsBootDisplayModeSupported = mSurfaceControlProxy.getBootDisplayModeSupport();
}
@Override
@@ -349,8 +352,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
if (preferredRecord != null) {
int preferredModeId = preferredRecord.mMode.getModeId();
- if (mSurfaceControlProxy.getBootDisplayModeSupport()
- && mSystemPreferredModeId != preferredModeId) {
+ if (mIsBootDisplayModeSupported && mSystemPreferredModeId != preferredModeId) {
mSystemPreferredModeId = preferredModeId;
preferredModeChanged = true;
}
@@ -900,7 +902,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
updateDeviceInfoLocked();
- if (!mSurfaceControlProxy.getBootDisplayModeSupport()) {
+ if (!mIsBootDisplayModeSupported) {
return;
}
if (mUserPreferredModeId == INVALID_MODE_ID) {
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index 176c08c8da29..924db6a49eeb 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -22,12 +22,14 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ILocaleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.res.Configuration;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.LocaleList;
@@ -154,6 +156,12 @@ public class LocaleManagerService extends SystemService {
}
@Override
+ @NonNull
+ public LocaleList getSystemLocales() throws RemoteException {
+ return LocaleManagerService.this.getSystemLocales();
+ }
+
+ @Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
@@ -426,6 +434,32 @@ public class LocaleManagerService extends SystemService {
return null;
}
+ /**
+ * Returns the current system locales.
+ */
+ @NonNull
+ public LocaleList getSystemLocales() throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return getSystemLocalesUnchecked();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @NonNull
+ private LocaleList getSystemLocalesUnchecked() throws RemoteException {
+ LocaleList systemLocales = null;
+ Configuration conf = ActivityManager.getService().getConfiguration();
+ if (conf != null) {
+ systemLocales = conf.getLocales();
+ }
+ if (systemLocales == null) {
+ systemLocales = LocaleList.getEmptyLocaleList();
+ }
+ return systemLocales;
+ }
+
private void logMetric(@NonNull AppLocaleChangedAtomRecord atomRecordForMetrics) {
FrameworkStatsLog.write(FrameworkStatsLog.APPLICATION_LOCALES_CHANGED,
atomRecordForMetrics.mCallingUid,
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/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 3ce8e4659737..1937852fa333 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -45,6 +45,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
+import android.window.WindowContainerToken;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
@@ -410,6 +411,7 @@ public final class MediaProjectionManagerService extends SystemService
private IBinder mToken;
private IBinder.DeathRecipient mDeathEater;
private boolean mRestoreSystemAlertWindow;
+ private WindowContainerToken mTaskRecordingWindowContainerToken = null;
MediaProjection(int type, int uid, String packageName, int targetSdkVersion,
boolean isPrivileged) {
@@ -568,7 +570,7 @@ public final class MediaProjectionManagerService extends SystemService
}
}
- @Override
+ @Override // Binder call
public void registerCallback(IMediaProjectionCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
@@ -576,7 +578,7 @@ public final class MediaProjectionManagerService extends SystemService
mCallbackDelegate.add(callback);
}
- @Override
+ @Override // Binder call
public void unregisterCallback(IMediaProjectionCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
@@ -584,6 +586,17 @@ public final class MediaProjectionManagerService extends SystemService
mCallbackDelegate.remove(callback);
}
+ @Override // Binder call
+ public void setTaskRecordingWindowContainerToken(WindowContainerToken token) {
+ // TODO(b/221417940) set the task id to record from sysui, for the package chosen.
+ mTaskRecordingWindowContainerToken = token;
+ }
+
+ @Override // Binder call
+ public WindowContainerToken getTaskRecordingWindowContainerToken() {
+ return mTaskRecordingWindowContainerToken;
+ }
+
public MediaProjectionInfo getProjectionInfo() {
return new MediaProjectionInfo(packageName, userHandle);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 35f6a94f3ed6..57ffba70ba2e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -5421,6 +5421,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, enable);
mLogger.meteredAllowlistChanged(uid, enable);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setUidOnMeteredNetworkDenylist(sdkSandboxUid, enable);
+ mLogger.meteredAllowlistChanged(sdkSandboxUid, enable);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting denylist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5433,6 +5438,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, enable);
mLogger.meteredDenylistChanged(uid, enable);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setUidOnMeteredNetworkAllowlist(sdkSandboxUid, enable);
+ mLogger.meteredDenylistChanged(sdkSandboxUid, enable);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting allowlist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5471,12 +5481,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private void addSdkSandboxUidsIfNeeded(SparseIntArray uidRules) {
+ final int size = uidRules.size();
+ final SparseIntArray sdkSandboxUids = new SparseIntArray();
+ for (int index = 0; index < size; index++) {
+ final int uid = uidRules.keyAt(index);
+ final int rule = uidRules.valueAt(index);
+ if (Process.isApplicationUid(uid)) {
+ sdkSandboxUids.put(Process.toSdkSandboxUid(uid), rule);
+ }
+ }
+
+ for (int index = 0; index < sdkSandboxUids.size(); index++) {
+ final int uid = sdkSandboxUids.keyAt(index);
+ final int rule = sdkSandboxUids.valueAt(index);
+ uidRules.put(uid, rule);
+ }
+ }
+
/**
* Set uid rules on a particular firewall chain. This is going to synchronize the rules given
* here to netd. It will clean up dead rules and make sure the target chain only contains rules
* specified here.
*/
private void setUidFirewallRulesUL(int chain, SparseIntArray uidRules) {
+ addSdkSandboxUidsIfNeeded(uidRules);
try {
int size = uidRules.size();
int[] uids = new int[size];
@@ -5519,6 +5548,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
mNetworkManager.setFirewallUidRule(chain, uid, rule);
mLogger.uidFirewallRuleChanged(chain, uid, rule);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setFirewallUidRule(chain, sdkSandboxUid, rule);
+ mLogger.uidFirewallRuleChanged(chain, sdkSandboxUid, rule);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting firewall uid rules", e);
} catch (RemoteException e) {
@@ -5555,15 +5589,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*/
private void resetUidFirewallRules(int uid) {
try {
- mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
- FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
+ FIREWALL_RULE_DEFAULT);
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
mLogger.meteredAllowlistChanged(uid, false);
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
@@ -5573,6 +5608,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} catch (RemoteException e) {
// ignored; service lives in system_server
}
+ if (Process.isApplicationUid(uid)) {
+ resetUidFirewallRules(Process.toSdkSandboxUid(uid));
+ }
}
@Deprecated
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 9ff4aab83cff..d26a1ac4fba0 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -253,7 +253,8 @@ public final class BackgroundDexOptService {
*
* <p>This is only for shell command and only root or shell user can use this.
*
- * @param packageNames dex optimize the passed packages or all packages if null
+ * @param packageNames dex optimize the passed packages in the given order, or all packages in
+ * the default order if null
*
* @return true if dex optimization is complete. false if the task is cancelled or if there was
* an error.
@@ -268,11 +269,11 @@ public final class BackgroundDexOptService {
resetStatesForNewDexOptRunLocked(Thread.currentThread());
}
PackageManagerService pm = mInjector.getPackageManagerService();
- ArraySet<String> packagesToOptimize;
+ List<String> packagesToOptimize;
if (packageNames == null) {
packagesToOptimize = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
} else {
- packagesToOptimize = new ArraySet<>(packageNames);
+ packagesToOptimize = packageNames;
}
return runIdleOptimization(pm, packagesToOptimize, /* isPostBootUpdate= */ false);
} finally {
@@ -335,7 +336,7 @@ public final class BackgroundDexOptService {
return false;
}
- ArraySet<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
+ List<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
if (pkgs.isEmpty()) {
Slog.i(TAG, "No packages to optimize");
markPostBootUpdateCompleted(params);
@@ -525,7 +526,7 @@ public final class BackgroundDexOptService {
}
/** Returns true if completed */
- private boolean runIdleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
+ private boolean runIdleOptimization(PackageManagerService pm, List<String> pkgs,
boolean isPostBootUpdate) {
synchronized (mLock) {
mLastExecutionStartTimeMs = SystemClock.elapsedRealtime();
@@ -581,10 +582,9 @@ public final class BackgroundDexOptService {
}
@Status
- private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+ private int idleOptimizePackages(PackageManagerService pm, List<String> pkgs,
long lowStorageThreshold, boolean isPostBootUpdate) {
ArraySet<String> updatedPackages = new ArraySet<>();
- ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>();
try {
boolean supportSecondaryDex = mInjector.supportSecondaryDex();
@@ -640,25 +640,12 @@ public final class BackgroundDexOptService {
}
}
- pkgs = new ArraySet<>(pkgs);
+ pkgs = new ArrayList<>(pkgs);
pkgs.removeAll(unusedPackages);
}
}
- @Status int primaryResult = optimizePackages(pkgs, lowStorageThreshold,
- /*isForPrimaryDex=*/ true, updatedPackages, isPostBootUpdate);
- if (primaryResult != STATUS_OK) {
- return primaryResult;
- }
-
- if (!supportSecondaryDex) {
- return STATUS_OK;
- }
-
- @Status int secondaryResult = optimizePackages(pkgs, lowStorageThreshold,
- /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex,
- isPostBootUpdate);
- return secondaryResult;
+ return optimizePackages(pkgs, lowStorageThreshold, updatedPackages, isPostBootUpdate);
} finally {
// Always let the pinner service know about changes.
notifyPinService(updatedPackages);
@@ -670,8 +657,10 @@ public final class BackgroundDexOptService {
}
@Status
- private int optimizePackages(ArraySet<String> pkgs, long lowStorageThreshold,
- boolean isForPrimaryDex, ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+ private int optimizePackages(List<String> pkgs, long lowStorageThreshold,
+ ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+ boolean supportSecondaryDex = mInjector.supportSecondaryDex();
+
for (String pkg : pkgs) {
int abortCode = abortIdleOptimizations(lowStorageThreshold);
if (abortCode != STATUS_OK) {
@@ -679,11 +668,23 @@ public final class BackgroundDexOptService {
return abortCode;
}
- @DexOptResult int result = optimizePackage(pkg, isForPrimaryDex, isPostBootUpdate);
- if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
+ @DexOptResult int primaryResult =
+ optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate);
+ if (primaryResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
updatedPackages.add(pkg);
- } else if (result != PackageDexOptimizer.DEX_OPT_SKIPPED) {
- return convertPackageDexOptimizerStatusToInternal(result);
+ } else if (primaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+ return convertPackageDexOptimizerStatusToInternal(primaryResult);
+ }
+
+ if (!supportSecondaryDex) {
+ continue;
+ }
+
+ @DexOptResult int secondaryResult =
+ optimizePackage(pkg, false /* isForPrimaryDex */, isPostBootUpdate);
+ if (secondaryResult != PackageDexOptimizer.DEX_OPT_PERFORMED
+ && secondaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+ return convertPackageDexOptimizerStatusToInternal(secondaryResult);
}
}
return STATUS_OK;
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 50b2e2321886..bb2ba5cc498d 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -293,8 +293,8 @@ final class DexOptHelper {
MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds);
}
- public ArraySet<String> getOptimizablePackages(@NonNull Computer snapshot) {
- ArraySet<String> pkgs = new ArraySet<>();
+ public List<String> getOptimizablePackages(@NonNull Computer snapshot) {
+ ArrayList<String> pkgs = new ArrayList<>();
mPm.forEachPackageState(snapshot, packageState -> {
final AndroidPackage pkg = packageState.getPkg();
if (pkg != null && mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) {
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index 91750dee7688..15f26e7a6d6c 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -32,6 +32,7 @@ import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_CHECK_MAX_SDK_VERSION;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.os.Environment;
@@ -61,14 +62,24 @@ import java.util.concurrent.ExecutorService;
* further cleanup and eventually all the installation/scanning related logic will go to another
* class.
*/
-final class InitAndSystemPackageHelper {
+final class InitAppsHelper {
private final PackageManagerService mPm;
-
private final List<ScanPartition> mDirsToScanAsSystem;
private final int mScanFlags;
private final int mSystemParseFlags;
private final int mSystemScanFlags;
private final InstallPackageHelper mInstallPackageHelper;
+ private final ApexManager mApexManager;
+ private final ExecutorService mExecutorService;
+ /* Tracks how long system scan took */
+ private long mSystemScanTime;
+ /* Track of the number of cached system apps */
+ private int mCachedSystemApps;
+ /* Track of the number of system apps */
+ private int mSystemPackagesCount;
+ private final boolean mIsDeviceUpgrading;
+ private final boolean mIsOnlyCoreApps;
+ private final List<ScanPartition> mSystemPartitions;
/**
* Tracks new system packages [received in an OTA] that we expect to
@@ -76,21 +87,33 @@ final class InitAndSystemPackageHelper {
* are package location.
*/
private final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+ /* Tracks of any system packages that no longer exist that needs to be pruned. */
+ private final List<String> mPossiblyDeletedUpdatedSystemApps = new ArrayList<>();
+ // Tracks of stub packages that must either be replaced with full versions in the /data
+ // partition or be disabled.
+ private final List<String> mStubSystemApps = new ArrayList<>();
// TODO(b/198166813): remove PMS dependency
- InitAndSystemPackageHelper(PackageManagerService pm) {
+ InitAppsHelper(PackageManagerService pm, ApexManager apexManager,
+ InstallPackageHelper installPackageHelper,
+ List<ScanPartition> systemPartitions) {
mPm = pm;
- mInstallPackageHelper = new InstallPackageHelper(pm);
+ mApexManager = apexManager;
+ mInstallPackageHelper = installPackageHelper;
+ mSystemPartitions = systemPartitions;
mDirsToScanAsSystem = getSystemScanPartitions();
+ mIsDeviceUpgrading = mPm.isDeviceUpgrading();
+ mIsOnlyCoreApps = mPm.isOnlyCoreApps();
// Set flag to monitor and not change apk file paths when scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
- if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()) {
+ if (mIsDeviceUpgrading || mPm.isFirstBoot()) {
mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
} else {
mScanFlags = scanFlags;
}
mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
+ mExecutorService = ParallelPackageParser.makeExecutorService();
}
private List<File> getFrameworkResApkSplitFiles() {
@@ -118,7 +141,7 @@ final class InitAndSystemPackageHelper {
private List<ScanPartition> getSystemScanPartitions() {
final List<ScanPartition> scanPartitions = new ArrayList<>();
- scanPartitions.addAll(mPm.mInjector.getSystemPartitions());
+ scanPartitions.addAll(mSystemPartitions);
scanPartitions.addAll(getApexScanPartitions());
Slog.d(TAG, "Directories scanned as system partitions: " + scanPartitions);
return scanPartitions;
@@ -126,8 +149,7 @@ final class InitAndSystemPackageHelper {
private List<ScanPartition> getApexScanPartitions() {
final List<ScanPartition> scanPartitions = new ArrayList<>();
- final List<ApexManager.ActiveApexInfo> activeApexInfos =
- mPm.mApexManager.getActiveApexInfos();
+ final List<ApexManager.ActiveApexInfo> activeApexInfos = mApexManager.getActiveApexInfos();
for (int i = 0; i < activeApexInfos.size(); i++) {
final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
if (scanPartition != null) {
@@ -144,117 +166,134 @@ final class InitAndSystemPackageHelper {
if (apexInfo.preInstalledApexPath.getAbsolutePath().equals(
sp.getFolder().getAbsolutePath())
|| apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
- sp.getFolder().getAbsolutePath() + File.separator)) {
+ sp.getFolder().getAbsolutePath() + File.separator)) {
return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
}
}
return null;
}
- public OverlayConfig initPackages(
- WatchedArrayMap<String, PackageSetting> packageSettings, int[] userIds,
- long startTime) {
- PackageParser2 packageParser = mPm.mInjector.getScanningCachingPackageParser();
-
- ExecutorService executorService = ParallelPackageParser.makeExecutorService();
+ /**
+ * Install apps from system dirs.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ public OverlayConfig initSystemApps(PackageParser2 packageParser,
+ WatchedArrayMap<String, PackageSetting> packageSettings,
+ int[] userIds, long startTime) {
// Prepare apex package info before scanning APKs, this information is needed when
// scanning apk in apex.
- mPm.mApexManager.scanApexPackagesTraced(packageParser, executorService);
+ mApexManager.scanApexPackagesTraced(packageParser, mExecutorService);
- scanSystemDirs(packageParser, executorService);
+ scanSystemDirs(packageParser, mExecutorService);
// Parse overlay configuration files to set default enable state, mutability, and
// priority of system overlays.
final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>();
- for (ApexManager.ActiveApexInfo apexInfo : mPm.mApexManager.getActiveApexInfos()) {
- for (String packageName : mPm.mApexManager.getApksInApex(apexInfo.apexModuleName)) {
+ for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {
+ for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) {
apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);
}
}
- OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
+ final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
consumer -> mPm.forEachPackage(mPm.snapshotComputer(),
pkg -> consumer.accept(pkg, pkg.isSystem(),
- apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
- // Prune any system packages that no longer exist.
- final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
- // Stub packages must either be replaced with full versions in the /data
- // partition or be disabled.
- final List<String> stubSystemApps = new ArrayList<>();
-
- if (!mPm.isOnlyCoreApps()) {
+ apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
+
+ if (!mIsOnlyCoreApps) {
// do this first before mucking with mPackages for the "expecting better" case
- updateStubSystemAppsList(stubSystemApps);
+ updateStubSystemAppsList(mStubSystemApps);
mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
- possiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
+ mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
}
- final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
+ logSystemAppsScanningTime(startTime);
+ return overlayConfig;
+ }
+
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void logSystemAppsScanningTime(long startTime) {
+ mCachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
// Remove any shared userIDs that have no associated packages
mPm.mSettings.pruneSharedUsersLPw();
- final long systemScanTime = SystemClock.uptimeMillis() - startTime;
- final int systemPackagesCount = mPm.mPackages.size();
- Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
- + " ms, packageCount: " + systemPackagesCount
+ mSystemScanTime = SystemClock.uptimeMillis() - startTime;
+ mSystemPackagesCount = mPm.mPackages.size();
+ Slog.i(TAG, "Finished scanning system apps. Time: " + mSystemScanTime
+ + " ms, packageCount: " + mSystemPackagesCount
+ " , timePerPackage: "
- + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
- + " , cached: " + cachedSystemApps);
- if (mPm.isDeviceUpgrading() && systemPackagesCount > 0) {
+ + (mSystemPackagesCount == 0 ? 0 : mSystemScanTime / mSystemPackagesCount)
+ + " , cached: " + mCachedSystemApps);
+ if (mIsDeviceUpgrading && mSystemPackagesCount > 0) {
//CHECKSTYLE:OFF IndentationCheck
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
- systemScanTime / systemPackagesCount);
+ mSystemScanTime / mSystemPackagesCount);
//CHECKSTYLE:ON IndentationCheck
}
+ }
- if (!mPm.isOnlyCoreApps()) {
+ /**
+ * Install apps/updates from data dir and fix system apps that are affected.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ public void initNonSystemApps(PackageParser2 packageParser, @NonNull int[] userIds,
+ long startTime) {
+ if (!mIsOnlyCoreApps) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
- mScanFlags | SCAN_REQUIRE_KNOWN, 0,
- packageParser, executorService);
-
+ mScanFlags | SCAN_REQUIRE_KNOWN,
+ packageParser, mExecutorService);
}
- List<Runnable> unfinishedTasks = executorService.shutdownNow();
+ List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
if (!unfinishedTasks.isEmpty()) {
throw new IllegalStateException("Not all tasks finished before calling close: "
+ unfinishedTasks);
}
-
- if (!mPm.isOnlyCoreApps()) {
- mInstallPackageHelper.cleanupDisabledPackageSettings(possiblyDeletedUpdatedSystemApps,
- userIds, mScanFlags);
- mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
- stubSystemApps, mSystemScanFlags, mSystemParseFlags);
-
- // Uncompress and install any stubbed system applications.
- // This must be done last to ensure all stubs are replaced or disabled.
- mInstallPackageHelper.installSystemStubPackages(stubSystemApps, mScanFlags);
-
- final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
- - cachedSystemApps;
-
- final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
- final int dataPackagesCount = mPm.mPackages.size() - systemPackagesCount;
- Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
- + " ms, packageCount: " + dataPackagesCount
- + " , timePerPackage: "
- + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
- + " , cached: " + cachedNonSystemApps);
- if (mPm.isDeviceUpgrading() && dataPackagesCount > 0) {
- //CHECKSTYLE:OFF IndentationCheck
- FrameworkStatsLog.write(
- FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
- BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
- dataScanTime / dataPackagesCount);
- //CHECKSTYLE:OFF IndentationCheck
- }
+ if (!mIsOnlyCoreApps) {
+ fixSystemPackages(userIds);
+ logNonSystemAppScanningTime(startTime);
}
mExpectingBetter.clear();
-
mPm.mSettings.pruneRenamedPackagesLPw();
- packageParser.close();
- return overlayConfig;
+ }
+
+ /**
+ * Clean up system packages now that some system package updates have been installed from
+ * the data dir. Also install system stub packages as the last step.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void fixSystemPackages(@NonNull int[] userIds) {
+ mInstallPackageHelper.cleanupDisabledPackageSettings(mPossiblyDeletedUpdatedSystemApps,
+ userIds, mScanFlags);
+ mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
+ mStubSystemApps, mSystemScanFlags, mSystemParseFlags);
+
+ // Uncompress and install any stubbed system applications.
+ // This must be done last to ensure all stubs are replaced or disabled.
+ mInstallPackageHelper.installSystemStubPackages(mStubSystemApps, mScanFlags);
+ }
+
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void logNonSystemAppScanningTime(long startTime) {
+ final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
+ - mCachedSystemApps;
+
+ final long dataScanTime = SystemClock.uptimeMillis() - mSystemScanTime - startTime;
+ final int dataPackagesCount = mPm.mPackages.size() - mSystemPackagesCount;
+ Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+ + " ms, packageCount: " + dataPackagesCount
+ + " , timePerPackage: "
+ + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+ + " , cached: " + cachedNonSystemApps);
+ if (mIsDeviceUpgrading && dataPackagesCount > 0) {
+ //CHECKSTYLE:OFF IndentationCheck
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+ BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+ dataScanTime / dataPackagesCount);
+ //CHECKSTYLE:OFF IndentationCheck
+ }
}
/**
@@ -274,13 +313,13 @@ final class InitAndSystemPackageHelper {
continue;
}
scanDirTracedLI(partition.getOverlayFolder(), /* frameworkSplits= */ null,
- mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+ mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService);
}
scanDirTracedLI(frameworkDir, null,
mSystemParseFlags,
- mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
+ mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
packageParser, executorService);
if (!mPm.mPackages.containsKey("android")) {
throw new IllegalStateException(
@@ -292,11 +331,11 @@ final class InitAndSystemPackageHelper {
if (partition.getPrivAppFolder() != null) {
scanDirTracedLI(partition.getPrivAppFolder(), /* frameworkSplits= */ null,
mSystemParseFlags,
- mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
+ mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
packageParser, executorService);
}
scanDirTracedLI(partition.getAppFolder(), /* frameworkSplits= */ null,
- mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+ mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService);
}
}
@@ -315,7 +354,7 @@ final class InitAndSystemPackageHelper {
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanDirTracedLI(File scanDir, List<File> frameworkSplits,
int parseFlags, int scanFlags,
- long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
+ PackageParser2 packageParser, ExecutorService executorService) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
@@ -323,7 +362,7 @@ final class InitAndSystemPackageHelper {
parseFlags |= PARSE_CHECK_MAX_SDK_VERSION;
}
mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags,
- scanFlags, currentTime, packageParser, executorService);
+ scanFlags, packageParser, executorService);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index b39b24f6defa..870a11ac2d61 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -3062,7 +3062,7 @@ final class InstallPackageHelper {
final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm);
removePackageHelper.removePackageLI(stubPkg, true /*chatty*/);
try {
- return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
+ return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
e);
@@ -3194,7 +3194,7 @@ final class InstallPackageHelper {
| ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
@PackageManagerService.ScanFlags int scanFlags = mPm.getSystemPackageScanFlags(codePath);
final AndroidPackage pkg = scanSystemPackageTracedLI(
- codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
+ codePath, parseFlags, scanFlags, null);
PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
@@ -3368,7 +3368,7 @@ final class InstallPackageHelper {
mRemovePackageHelper.removePackageLI(pkg, true);
try {
final File codePath = new File(pkg.getPath());
- scanSystemPackageTracedLI(codePath, 0, scanFlags, 0, null);
+ scanSystemPackageTracedLI(codePath, 0, scanFlags, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
+ e.getMessage());
@@ -3389,7 +3389,7 @@ final class InstallPackageHelper {
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
- int scanFlags, long currentTime, PackageParser2 packageParser,
+ int scanFlags, PackageParser2 packageParser,
ExecutorService executorService) {
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
@@ -3432,7 +3432,7 @@ final class InstallPackageHelper {
parseResult.parsedPackage);
}
try {
- addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime,
+ addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
null);
} catch (PackageManagerException e) {
errorCode = e.error;
@@ -3495,7 +3495,7 @@ final class InstallPackageHelper {
try {
final AndroidPackage newPkg = scanSystemPackageTracedLI(
- scanFile, reparseFlags, rescanFlags, 0, null);
+ scanFile, reparseFlags, rescanFlags, null);
// We rescanned a stub, add it to the list of stubbed system packages
if (newPkg.isStub()) {
stubSystemApps.add(packageName);
@@ -3509,14 +3509,14 @@ final class InstallPackageHelper {
/**
* Traces a package scan.
- * @see #scanSystemPackageLI(File, int, int, long, UserHandle)
+ * @see #scanSystemPackageLI(File, int, int, UserHandle)
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public AndroidPackage scanSystemPackageTracedLI(File scanFile, final int parseFlags,
- int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
+ int scanFlags, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
try {
- return scanSystemPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
+ return scanSystemPackageLI(scanFile, parseFlags, scanFlags, user);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -3528,7 +3528,7 @@ final class InstallPackageHelper {
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags,
- long currentTime, UserHandle user) throws PackageManagerException {
+ UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
@@ -3544,7 +3544,7 @@ final class InstallPackageHelper {
PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
}
- return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
+ return addForInitLI(parsedPackage, parseFlags, scanFlags, user);
}
/**
@@ -3563,11 +3563,11 @@ final class InstallPackageHelper {
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
- @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+ @PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user) throws PackageManagerException {
final Pair<ScanResult, Boolean> scanResultPair = scanSystemPackageLI(
- parsedPackage, parseFlags, scanFlags, currentTime, user);
+ parsedPackage, parseFlags, scanFlags, user);
final ScanResult scanResult = scanResultPair.first;
boolean shouldHideSystemApp = scanResultPair.second;
if (scanResult.mSuccess) {
@@ -3762,7 +3762,7 @@ final class InstallPackageHelper {
private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
- @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+ @PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user) throws PackageManagerException {
final boolean scanSystemPartition =
(parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
@@ -3950,7 +3950,7 @@ final class InstallPackageHelper {
}
final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags,
- scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
+ scanFlags | SCAN_UPDATE_SIGNATURE, 0 /* currentTime */, user, null);
return new Pair<>(scanResult, shouldHideSystemApp);
}
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/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index eaecb17103a5..b1b05bedfcad 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -229,7 +229,6 @@ import com.android.server.pm.resolution.ComponentResolverApi;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationService;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
-import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
import com.android.server.sdksandbox.SdkSandboxManagerLocal;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.utils.SnapshotCache;
@@ -936,7 +935,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
private final BroadcastHelper mBroadcastHelper;
private final RemovePackageHelper mRemovePackageHelper;
private final DeletePackageHelper mDeletePackageHelper;
- private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
+ private final InitAppsHelper mInitAppsHelper;
private final AppDataHelper mAppDataHelper;
private final InstallPackageHelper mInstallPackageHelper;
private final PreferredActivityHelper mPreferredActivityHelper;
@@ -1671,7 +1670,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mAppDataHelper = testParams.appDataHelper;
mInstallPackageHelper = testParams.installPackageHelper;
mRemovePackageHelper = testParams.removePackageHelper;
- mInitAndSystemPackageHelper = testParams.initAndSystemPackageHelper;
+ mInitAppsHelper = testParams.initAndSystemPackageHelper;
mDeletePackageHelper = testParams.deletePackageHelper;
mPreferredActivityHelper = testParams.preferredActivityHelper;
mResolveIntentHelper = testParams.resolveIntentHelper;
@@ -1821,7 +1820,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mAppDataHelper = new AppDataHelper(this);
mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper);
mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
- mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this);
+ mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
+ mInjector.getSystemPartitions());
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
mAppDataHelper);
mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
@@ -1956,8 +1956,11 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion);
final int[] userIds = mUserManager.getUserIds();
- mOverlayConfig = mInitAndSystemPackageHelper.initPackages(packageSettings,
- userIds, startTime);
+ PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
+ mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,
+ startTime);
+ mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime);
+ packageParser.close();
// Resolve the storage manager.
mStorageManagerPackage = getStorageManagerPackageName(computer);
@@ -7030,7 +7033,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
boolean isExpectingBetter(String packageName) {
- return mInitAndSystemPackageHelper.isExpectingBetter(packageName);
+ return mInitAppsHelper.isExpectingBetter(packageName);
}
int getDefParseFlags() {
@@ -7129,13 +7132,12 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
boolean isOverlayMutable(String packageName) {
- return (mOverlayConfig != null ? mOverlayConfig
- : OverlayConfig.getSystemInstance()).isMutable(packageName);
+ return mOverlayConfig.isMutable(packageName);
}
@ScanFlags int getSystemPackageScanFlags(File codePath) {
List<ScanPartition> dirsToScanAsSystem =
- mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+ mInitAppsHelper.getDirsToScanAsSystem();
@PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
ScanPartition partition = dirsToScanAsSystem.get(i);
@@ -7153,7 +7155,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
Pair<Integer, Integer> getSystemPackageRescanFlagsAndReparseFlags(File scanFile,
int systemScanFlags, int systemParseFlags) {
List<ScanPartition> dirsToScanAsSystem =
- mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+ mInitAppsHelper.getDirsToScanAsSystem();
@ParsingPackageUtils.ParseFlags int reparseFlags = 0;
@PackageManagerService.ScanFlags int rescanFlags = 0;
for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 5bdda0b3c1d8..e466fe2c0e31 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -109,7 +109,7 @@ public final class PackageManagerServiceTestParams {
public AppDataHelper appDataHelper;
public InstallPackageHelper installPackageHelper;
public RemovePackageHelper removePackageHelper;
- public InitAndSystemPackageHelper initAndSystemPackageHelper;
+ public InitAppsHelper initAndSystemPackageHelper;
public DeletePackageHelper deletePackageHelper;
public PreferredActivityHelper preferredActivityHelper;
public ResolveIntentHelper resolveIntentHelper;
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/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index df19d3e58bfd..a991ed3c4792 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -151,7 +151,7 @@ public final class StorageEventHelper extends StorageEventListener {
final AndroidPackage pkg;
try {
pkg = installPackageHelper.scanSystemPackageTracedLI(
- ps.getPath(), parseFlags, SCAN_INITIAL, 0, null);
+ ps.getPath(), parseFlags, SCAN_INITIAL, null);
loaded.add(pkg);
} catch (PackageManagerException e) {
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/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 34b7ad41e540..70053bdeb47e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -5409,6 +5409,21 @@ public class UserManagerService extends IUserManager.Stub {
(new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
}
+ private static final String PREFIX_HELP_COMMAND = " ";
+ private static final String PREFIX_HELP_DESCRIPTION = " ";
+ private static final String PREFIX_HELP_DESCRIPTION_EXTRA_LINES = " ";
+
+ private static final String CMD_HELP = "help";
+ private static final String CMD_LIST = "list";
+ private static final String CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS =
+ "report-system-user-package-whitelist-problems";
+
+ private static final String ARG_V = "-v";
+ private static final String ARG_VERBOSE = "--verbose";
+ private static final String ARG_ALL = "--all";
+ private static final String ARG_CRITICAL_ONLY = "--critical-only";
+ private static final String ARG_MODE = "--mode";
+
private int onShellCommand(Shell shell, String cmd) {
if (cmd == null) {
return shell.handleDefaultCommands(cmd);
@@ -5417,9 +5432,9 @@ public class UserManagerService extends IUserManager.Stub {
final PrintWriter pw = shell.getOutPrintWriter();
try {
switch(cmd) {
- case "list":
+ case CMD_LIST:
return runList(pw, shell);
- case "report-system-user-package-whitelist-problems":
+ case CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS:
return runReportPackageWhitelistProblems(pw, shell);
default:
return shell.handleDefaultCommands(cmd);
@@ -5436,10 +5451,10 @@ public class UserManagerService extends IUserManager.Stub {
String opt;
while ((opt = shell.getNextOption()) != null) {
switch (opt) {
- case "-v":
+ case ARG_V:
verbose = true;
break;
- case "--all":
+ case ARG_ALL:
all = true;
break;
default:
@@ -5520,14 +5535,14 @@ public class UserManagerService extends IUserManager.Stub {
String opt;
while ((opt = shell.getNextOption()) != null) {
switch (opt) {
- case "-v":
- case "--verbose":
+ case ARG_V:
+ case ARG_VERBOSE:
verbose = true;
break;
- case "--critical-only":
+ case ARG_CRITICAL_ONLY:
criticalOnly = true;
break;
- case "--mode":
+ case ARG_MODE:
mode = Integer.parseInt(shell.getNextArgRequired());
break;
default:
@@ -6248,20 +6263,28 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
- pw.println("User manager (user) commands:");
- pw.println(" help");
- pw.println(" Prints this help text.");
- pw.println("");
- pw.println(" list [-v] [-all]");
- pw.println(" Prints all users on the system.");
- pw.println(" report-system-user-package-whitelist-problems [-v | --verbose] "
- + "[--critical-only] [--mode MODE]");
- pw.println(" Reports all issues on user-type package whitelist XML files. Options:");
- pw.println(" -v | --verbose : shows extra info, like number of issues");
- pw.println(" --critical-only: show only critical issues, excluding warnings");
- pw.println(" --mode MODE: shows what errors would be if device used mode MODE (where"
- + " MODE is the whitelist mode integer as defined by "
- + "config_userTypePackageWhitelistMode)");
+ pw.printf("User manager (user) commands:\n");
+
+ pw.printf("%s%s\n", PREFIX_HELP_COMMAND, CMD_HELP);
+ pw.printf("%sPrints this help text.\n\n", PREFIX_HELP_DESCRIPTION);
+
+ pw.printf("%s%s [%s] [%s]\n", PREFIX_HELP_COMMAND, CMD_LIST, ARG_V, ARG_ALL);
+ pw.printf("%sPrints all users on the system.\n\n", PREFIX_HELP_DESCRIPTION);
+
+ pw.printf("%s%s [%s | %s] [%s] [%s MODE]\n", PREFIX_HELP_COMMAND,
+ CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS,
+ ARG_V, ARG_VERBOSE, ARG_CRITICAL_ONLY, ARG_MODE);
+
+ pw.printf("%sReports all issues on user-type package allowlist XML files. Options:\n",
+ PREFIX_HELP_DESCRIPTION);
+ pw.printf("%s%s | %s: shows extra info, like number of issues\n",
+ PREFIX_HELP_DESCRIPTION, ARG_V, ARG_VERBOSE);
+ pw.printf("%s%s: show only critical issues, excluding warnings\n",
+ PREFIX_HELP_DESCRIPTION, ARG_CRITICAL_ONLY);
+ pw.printf("%s%s MODE: shows what errors would be if device used mode MODE\n"
+ + "%s(where MODE is the allowlist mode integer as defined by "
+ + "config_userTypePackageWhitelistMode)\n\n",
+ PREFIX_HELP_DESCRIPTION, ARG_MODE, PREFIX_HELP_DESCRIPTION_EXTRA_LINES);
}
}
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index 46fde4b59d8b..60602337ba1a 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -272,6 +272,10 @@ public class OneTimePermissionUserManager {
mHandler.removeCallbacksAndMessages(mToken);
if (importance > IMPORTANCE_CACHED) {
+ if (mRevokeAfterKilledDelay == 0) {
+ onPackageInactiveLocked();
+ return;
+ }
// Delay revocation in case app is restarting
mHandler.postDelayed(() -> {
int imp = mActivityManager.getUidImportance(mUid);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 71554eee3127..5a05134bed81 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -562,12 +562,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
- @NonNull List<String> permissions) {
- mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions);
- }
-
- @Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
int userId) {
return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index d0609307e6a8..009d155e96ef 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -1597,25 +1597,6 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
}
- @Override
- public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions) {
- final int callingUid = Binder.getCallingUid();
- int callingUserId = UserHandle.getUserId(callingUid);
- int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
- if (targetPackageUid != callingUid) {
- throw new SecurityException("uid " + callingUid
- + " cannot revoke permissions for package " + packageName + " with uid "
- + targetPackageUid);
- }
- for (String permName : permissions) {
- if (!checkCallingOrSelfPermission(permName)) {
- throw new SecurityException("uid " + callingUid + " cannot revoke permission "
- + permName + " because it does not hold that permission");
- }
- }
- mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions);
- }
-
private boolean mayManageRolePermission(int uid) {
final PackageManager packageManager = mContext.getPackageManager();
final String[] packageNames = packageManager.getPackagesForUid(uid);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 3e28320a2130..3771f030aefa 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -327,28 +327,6 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId);
/**
- * Triggers the revocation of one or more permissions for a package, under the following
- * conditions:
- * <ul>
- * <li>The package {@code packageName} must be under the same UID as the calling process
- * (typically, the target package is the calling package).
- * <li>Each permission in {@code permissions} must be granted to the package
- * {@code packageName}.
- * <li>Each permission in {@code permissions} must be a runtime permission.
- * </ul>
- * <p>
- * Background permissions which have no corresponding foreground permission still granted once
- * the revocation is effective will also be revoked.
- * <p>
- * This revocation happens asynchronously and kills all processes running in the same UID as
- * {@code packageName}. It will be triggered once it is safe to do so.
- *
- * @param packageName The name of the package for which the permissions will be revoked.
- * @param permissions List of permissions to be revoked.
- */
- void revokeOwnPermissionsOnKill(String packageName, List<String> permissions);
-
- /**
* Get whether you should show UI with rationale for requesting a permission. You should do this
* only if you do not have the permission and the context in which the permission is requested
* does not clearly communicate to the user what would be the benefit from grating this
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 2e60f130bc4b..526dccb72e39 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1633,7 +1633,14 @@ public class StatsPullAtomService extends SystemService {
if (adapter != null) {
SynchronousResultReceiver bluetoothReceiver =
new SynchronousResultReceiver("bluetooth");
- adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+ adapter.requestControllerActivityEnergyInfo(
+ Runnable::run,
+ info -> {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
+ bluetoothReceiver.send(0, bundle);
+ }
+ );
return awaitControllerInfo(bluetoothReceiver);
} else {
Slog.e(TAG, "Failed to get bluetooth adapter!");
@@ -2338,51 +2345,25 @@ public class StatsPullAtomService extends SystemService {
}
int pullProcessDmabufMemory(int atomTag, List<StatsEvent> pulledData) {
- List<ProcessMemoryState> managedProcessList =
- LocalServices.getService(ActivityManagerInternal.class)
- .getMemoryStateForProcesses();
- for (ProcessMemoryState process : managedProcessList) {
- KernelAllocationStats.ProcessDmabuf proc =
- KernelAllocationStats.getDmabufAllocations(process.pid);
- if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
- continue;
- }
- pulledData.add(
- FrameworkStatsLog.buildStatsEvent(
- atomTag,
- process.uid,
- process.processName,
- process.oomScore,
- proc.retainedSizeKb,
- proc.retainedBuffersCount,
- proc.mappedSizeKb,
- proc.mappedBuffersCount));
+ KernelAllocationStats.ProcessDmabuf[] procBufs =
+ KernelAllocationStats.getDmabufAllocations();
+
+ if (procBufs == null) {
+ return StatsManager.PULL_SKIP;
}
- SparseArray<String> processCmdlines = getProcessCmdlines();
- managedProcessList.forEach(managedProcess -> processCmdlines.delete(managedProcess.pid));
- int size = processCmdlines.size();
- for (int i = 0; i < size; ++i) {
- int pid = processCmdlines.keyAt(i);
- int uid = getUidForPid(pid);
- // ignore root processes (unlikely to be interesting)
- if (uid <= 0) {
- continue;
- }
- KernelAllocationStats.ProcessDmabuf proc =
- KernelAllocationStats.getDmabufAllocations(pid);
- if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
- continue;
- }
- pulledData.add(
- FrameworkStatsLog.buildStatsEvent(
- atomTag,
- uid,
- processCmdlines.valueAt(i),
- -1001 /*Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.*/,
- proc.retainedSizeKb,
- proc.retainedBuffersCount,
- proc.mappedSizeKb,
- proc.mappedBuffersCount));
+ for (KernelAllocationStats.ProcessDmabuf procBuf : procBufs) {
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag,
+ procBuf.uid,
+ procBuf.processName,
+ procBuf.oomScore,
+ procBuf.retainedSizeKb,
+ procBuf.retainedBuffersCount,
+ 0, /* mapped_dmabuf_kb - deprecated */
+ 0, /* mapped_dmabuf_count - deprecated */
+ procBuf.surfaceFlingerSizeKb,
+ procBuf.surfaceFlingerCount
+ ));
}
return StatsManager.PULL_SUCCESS;
}
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..c252043028c9 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -1360,6 +1360,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,
@@ -2221,6 +2247,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/utils/TimingsTraceAndSlog.java b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
index 397acfac2812..b45c962811ad 100644
--- a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
+++ b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
@@ -88,7 +88,7 @@ public final class TimingsTraceAndSlog extends TimingsTraceLog {
@Override
public void traceBegin(@NonNull String name) {
- Slog.i(mTag, name);
+ Slog.d(mTag, name);
super.traceBegin(name);
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index c0cdec9ade7f..7f84f61a91ff 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -191,6 +191,35 @@ class ActivityMetricsLogger {
private long mCurrentTransitionStartTimeNs;
/** Non-null when a {@link TransitionInfo} is created for this state. */
private TransitionInfo mAssociatedTransitionInfo;
+ /** The sequence id for trace. It is used to map the traces before resolving intent. */
+ private static int sTraceSeqId;
+ /** The trace format is "launchingActivity#$seqId:$state(:$packageName)". */
+ final String mTraceName;
+
+ LaunchingState() {
+ if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ mTraceName = null;
+ return;
+ }
+ // Use an id because the launching app is not yet known before resolving intent.
+ sTraceSeqId++;
+ mTraceName = "launchingActivity#" + sTraceSeqId;
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
+ }
+
+ void stopTrace(boolean abort) {
+ if (mTraceName == null) return;
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
+ final String launchResult;
+ if (mAssociatedTransitionInfo == null) {
+ launchResult = ":failed";
+ } else {
+ launchResult = (abort ? ":canceled:" : ":completed:")
+ + mAssociatedTransitionInfo.mLastLaunchedActivity.packageName;
+ }
+ // Put a supplement trace as the description of the async trace with the same id.
+ Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName + launchResult);
+ }
@VisibleForTesting
boolean allDrawn() {
@@ -549,10 +578,10 @@ class ActivityMetricsLogger {
}
if (existingInfo == null) {
- // Only notify the observer for a new launching event.
- launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
final LaunchingState launchingState = new LaunchingState();
launchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
+ // Only notify the observer for a new launching event.
+ launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
return launchingState;
}
existingInfo.mLaunchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
@@ -574,7 +603,7 @@ class ActivityMetricsLogger {
@Nullable ActivityOptions options) {
if (launchedActivity == null) {
// The launch is aborted, e.g. intent not resolved, class not found.
- abort(null /* info */, "nothing launched");
+ abort(launchingState, "nothing launched");
return;
}
@@ -601,7 +630,7 @@ class ActivityMetricsLogger {
if (launchedActivity.isReportedDrawn() && launchedActivity.isVisible()) {
// Launched activity is already visible. We cannot measure windows drawn delay.
- abort(info, "launched activity already visible");
+ abort(launchingState, "launched activity already visible");
return;
}
@@ -633,7 +662,7 @@ class ActivityMetricsLogger {
final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
options, processRunning, processSwitch, newActivityCreated, resultCode);
if (newInfo == null) {
- abort(info, "unrecognized launch");
+ abort(launchingState, "unrecognized launch");
return;
}
@@ -874,23 +903,29 @@ class ActivityMetricsLogger {
}
}
+ private void abort(@NonNull LaunchingState state, String cause) {
+ if (state.mAssociatedTransitionInfo != null) {
+ abort(state.mAssociatedTransitionInfo, cause);
+ return;
+ }
+ if (DEBUG_METRICS) Slog.i(TAG, "abort launch cause=" + cause);
+ state.stopTrace(true /* abort */);
+ launchObserverNotifyIntentFailed();
+ }
+
/** Aborts tracking of current launch metrics. */
- private void abort(TransitionInfo info, String cause) {
+ private void abort(@NonNull TransitionInfo info, String cause) {
done(true /* abort */, info, cause, 0L /* timestampNs */);
}
/** Called when the given transition (info) is no longer active. */
- private void done(boolean abort, @Nullable TransitionInfo info, String cause,
+ private void done(boolean abort, @NonNull TransitionInfo info, String cause,
long timestampNs) {
if (DEBUG_METRICS) {
Slog.i(TAG, "done abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
+ " info=" + info);
}
- if (info == null) {
- launchObserverNotifyIntentFailed();
- return;
- }
-
+ info.mLaunchingState.stopTrace(abort);
stopLaunchTrace(info);
final Boolean isHibernating =
mLastHibernationStates.remove(info.mLastLaunchedActivity.packageName);
@@ -1457,7 +1492,7 @@ class ActivityMetricsLogger {
/** Starts trace for an activity is actually launching. */
private void startLaunchTrace(@NonNull TransitionInfo info) {
if (DEBUG_METRICS) Slog.i(TAG, "startLaunchTrace " + info);
- if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ if (info.mLaunchingState.mTraceName == null) {
return;
}
info.mLaunchTraceName = "launching: " + info.mLastLaunchedActivity.packageName;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 883ce99d313d..bfe1f30f671a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5603,19 +5603,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
"makeInvisible", true /* beforeStopping */);
// Defer telling the client it is hidden if it can enter Pip and isn't current paused,
// stopped or stopping. This gives it a chance to enter Pip in onPause().
- // TODO: There is still a question surrounding activities in multi-window mode that want
- // to enter Pip after they are paused, but are still visible. I they should be okay to
- // enter Pip in those cases, but not "auto-Pip" which is what this condition covers and
- // the current contract for "auto-Pip" is that the app should enter it before onPause
- // returns. Just need to confirm this reasoning makes sense.
final boolean deferHidingClient = canEnterPictureInPicture
&& !isState(STARTED, STOPPING, STOPPED, PAUSED);
- if (!mTransitionController.isShellTransitionsEnabled()
- && deferHidingClient && pictureInPictureArgs.isAutoEnterEnabled()) {
- // Go ahead and just put the activity in pip if it supports auto-pip.
- mAtmService.enterPictureInPictureMode(this, pictureInPictureArgs);
- return;
- }
setDeferHidingClient(deferHidingClient);
setVisibility(false);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 7d2dfa071597..77ec67f31d50 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2730,10 +2730,11 @@ class ActivityStarter {
false /* includingParents */);
intentTask = intentTask.getParent().asTaskFragment().getTask();
}
- // If the task is in multi-windowing mode, the activity may already be on
+ // If the activity is visible in multi-windowing mode, it may already be on
// the top (visible to user but not the global top), then the result code
// should be START_DELIVERED_TO_TOP instead of START_TASK_TO_FRONT.
final boolean wasTopOfVisibleRootTask = intentActivity.mVisibleRequested
+ && intentActivity.inMultiWindowMode()
&& intentActivity == mTargetRootTask.topRunningActivity();
// We only want to move to the front, if we aren't going to launch on a
// different root task. If we launch on a different root task, we will put the
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 07a0c372778b..87523f44d4b6 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
+import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTENT_RECORDING;
@@ -26,6 +27,7 @@ import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
+import android.provider.DeviceConfig;
import android.view.ContentRecordingSession;
import android.view.Display;
import android.view.SurfaceControl;
@@ -39,6 +41,11 @@ import com.android.internal.protolog.common.ProtoLog;
final class ContentRecorder {
/**
+ * The key for accessing the device config that controls if task recording is supported.
+ */
+ @VisibleForTesting static final String KEY_RECORD_TASK_FEATURE = "record_task_content";
+
+ /**
* The display content this class is handling recording for.
*/
@NonNull
@@ -48,7 +55,7 @@ final class ContentRecorder {
* The session for content recording, or null if this DisplayContent is not being used for
* recording.
*/
- @VisibleForTesting private ContentRecordingSession mContentRecordingSession = null;
+ private ContentRecordingSession mContentRecordingSession = null;
/**
* The WindowContainer for the level of the hierarchy to record.
@@ -187,6 +194,8 @@ final class ContentRecorder {
mDisplayContent.mWmService.mTransactionFactory.get().remove(mRecordedSurface).apply();
mRecordedSurface = null;
clearContentRecordingSession();
+ // Do not need to force remove the VirtualDisplay; this is handled by the media
+ // projection service.
}
}
@@ -215,46 +224,12 @@ final class ContentRecorder {
return;
}
- final int contentToRecord = mContentRecordingSession.getContentToRecord();
- if (contentToRecord != RECORD_CONTENT_DISPLAY) {
- // TODO(b/216625226) handle task-based recording
- // Not a valid region, or recording is disabled, so fall back to prior MediaProjection
- // approach.
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to start recording due to invalid region for display %d",
- mDisplayContent.getDisplayId());
- return;
- }
- // Given the WindowToken of the DisplayArea to record, retrieve the associated
- // SurfaceControl.
- IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
- if (tokenToRecord == null) {
- // Unexpectedly missing token. Fall back to prior MediaProjection approach.
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to start recording due to null token for display %d",
- mDisplayContent.getDisplayId());
- return;
- }
-
- final WindowContainer wc =
- mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
- tokenToRecord);
- if (wc == null) {
- // Un-set the window token to record for this VirtualDisplay. Fall back to the
- // original MediaProjection approach.
- mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
- mDisplayContent.getDisplayId(), false);
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to retrieve window container to start recording for "
- + "display %d",
- mDisplayContent.getDisplayId());
+ mRecordedWindowContainer = retrieveRecordedWindowContainer();
+ if (mRecordedWindowContainer == null) {
+ // Either the token is missing, or the window associated with the token is missing.
+ // Error has already been handled, so just leave.
return;
}
- // TODO(206461622) Migrate to using the RootDisplayArea
- mRecordedWindowContainer = wc.getDisplayContent();
final Point surfaceSize = fetchSurfaceSizeIfPresent();
if (surfaceSize == null) {
@@ -296,6 +271,107 @@ final class ContentRecorder {
}
/**
+ * Retrieves the {@link WindowContainer} for the level of the hierarchy to start recording,
+ * indicated by the {@link #mContentRecordingSession}. Performs any error handling and state
+ * updates necessary if the {@link WindowContainer} could not be retrieved.
+ * {@link #mContentRecordingSession} must be non-null.
+ *
+ * @return a {@link WindowContainer} to record, or {@code null} if an error was encountered. The
+ * error is logged and any cleanup is handled.
+ */
+ @Nullable
+ private WindowContainer retrieveRecordedWindowContainer() {
+ final int contentToRecord = mContentRecordingSession.getContentToRecord();
+ // Given the WindowToken of the region to record, retrieve the associated
+ // SurfaceControl.
+ final IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
+ if (tokenToRecord == null) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to start recording due to null token for display %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ switch (contentToRecord) {
+ case RECORD_CONTENT_DISPLAY:
+ final WindowContainer wc =
+ mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
+ tokenToRecord);
+ if (wc == null) {
+ // Un-set the window token to record for this VirtualDisplay. Fall back to
+ // Display stack capture for the entire display.
+ mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
+ mDisplayContent.getDisplayId(), false);
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to retrieve window container to start recording for "
+ + "display %d", mDisplayContent.getDisplayId());
+ return null;
+ }
+ // TODO(206461622) Migrate to using the RootDisplayArea
+ return wc.getDisplayContent();
+ case RECORD_CONTENT_TASK:
+ if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_RECORD_TASK_FEATURE, false)) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to record task since feature is disabled %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ Task taskToRecord = WindowContainer.fromBinder(tokenToRecord).asTask();
+ if (taskToRecord == null) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to retrieve task to start recording for "
+ + "display %d", mDisplayContent.getDisplayId());
+ }
+ return taskToRecord;
+ default:
+ // Not a valid region, or recording is disabled, so fall back to Display stack
+ // capture for the entire display.
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to start recording due to invalid region for display %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ }
+
+ /**
+ * Exit this recording session.
+ * <p>
+ * If this is a task session, tear down the recording entirely. Do not fall back
+ * to recording the entire display on the display stack; this would surprise the user
+ * given they selected task capture.
+ * </p><p>
+ * If this is a display session, just stop recording by layer mirroring. Fall back to recording
+ * from the display stack.
+ * </p>
+ */
+ private void handleStartRecordingFailed() {
+ final boolean shouldExitTaskRecording = mContentRecordingSession != null
+ && mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK;
+ if (shouldExitTaskRecording) {
+ // Clean up the cached session first, since tearing down the display will generate
+ // display
+ // events which will trickle back to here.
+ clearContentRecordingSession();
+ tearDownVirtualDisplay();
+ } else {
+ clearContentRecordingSession();
+ }
+ }
+
+ /**
+ * Ensure recording does not fall back to the display stack; ensure the recording is stopped
+ * and the client notified by tearing down the virtual display.
+ */
+ private void tearDownVirtualDisplay() {
+ // TODO(b/219761722) Clean up the VirtualDisplay if task mirroring fails
+ }
+
+ /**
* Apply transformations to the mirrored surface to ensure the captured contents are scaled to
* fit and centred in the output surface.
*
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index d187bd6f3dfd..2ac41a7c1c1d 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1459,7 +1459,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// next activity.
final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState(
"shouldAutoPipWhilePausing", userLeaving);
- if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
+ if (userLeaving && lastResumedCanPip
+ && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
shouldAutoPip = true;
} else if (!lastResumedCanPip) {
// If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c50888b5a172..eb88b8b0ea97 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3278,7 +3278,7 @@ public class WindowManagerService extends IWindowManager.Stub
mContext.enforceCallingOrSelfPermission(
Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE,
Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE
- + " permission required to read keyguard visibility");
+ + " permission required to subscribe to keyguard locked state changes");
}
private void dispatchKeyguardLockedState() {
diff --git a/services/core/jni/gnss/MeasurementCorrections.cpp b/services/core/jni/gnss/MeasurementCorrections.cpp
index 8a3d84cbe9c6..07d0a45e9c40 100644
--- a/services/core/jni/gnss/MeasurementCorrections.cpp
+++ b/services/core/jni/gnss/MeasurementCorrections.cpp
@@ -44,6 +44,7 @@ using SingleSatCorrection_Aidl =
using ReflectingPlane_V1_0 =
android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane;
using ReflectingPlane_Aidl = android::hardware::gnss::measurement_corrections::ReflectingPlane;
+using ExcessPathInfo = SingleSatCorrection_Aidl::ExcessPathInfo;
using GnssConstellationType_V1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
using GnssConstellationType_V2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
using GnssConstellationType_Aidl = android::hardware::gnss::GnssConstellationType;
@@ -62,7 +63,7 @@ jmethodID method_correctionsHasEnvironmentBearing;
jmethodID method_correctionsGetEnvironmentBearingDegrees;
jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
jmethodID method_listSize;
-jmethodID method_correctionListGet;
+jmethodID method_listGet;
jmethodID method_correctionSatFlags;
jmethodID method_correctionSatConstType;
jmethodID method_correctionSatId;
@@ -71,10 +72,17 @@ jmethodID method_correctionSatIsLosProb;
jmethodID method_correctionSatEpl;
jmethodID method_correctionSatEplUnc;
jmethodID method_correctionSatRefPlane;
+jmethodID method_correctionSatAttenuation;
+jmethodID method_correctionSatExcessPathInfoList;
jmethodID method_correctionPlaneLatDeg;
jmethodID method_correctionPlaneLngDeg;
jmethodID method_correctionPlaneAltDeg;
jmethodID method_correctionPlaneAzimDeg;
+jmethodID method_excessPathInfoFlags;
+jmethodID method_excessPathInfoEpl;
+jmethodID method_excessPathInfoEplUnc;
+jmethodID method_excessPathInfoRefPlane;
+jmethodID method_excessPathInfoAttenuation;
} // anonymous namespace
void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
@@ -103,7 +111,7 @@ void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
jclass corrListClass = env->FindClass("java/util/List");
method_listSize = env->GetMethodID(corrListClass, "size", "()I");
- method_correctionListGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
+ method_listGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
jclass singleSatCorrClass = env->FindClass("android/location/GnssSingleSatCorrection");
method_correctionSatFlags =
@@ -121,12 +129,27 @@ void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
env->GetMethodID(singleSatCorrClass, "getExcessPathLengthUncertaintyMeters", "()F");
method_correctionSatRefPlane = env->GetMethodID(singleSatCorrClass, "getReflectingPlane",
"()Landroid/location/GnssReflectingPlane;");
+ method_correctionSatAttenuation =
+ env->GetMethodID(singleSatCorrClass, "getCombinedAttenuationDb", "()F");
+ method_correctionSatExcessPathInfoList =
+ env->GetMethodID(singleSatCorrClass, "getGnssExcessPathInfoList", "()Ljava/util/List;");
jclass refPlaneClass = env->FindClass("android/location/GnssReflectingPlane");
method_correctionPlaneLatDeg = env->GetMethodID(refPlaneClass, "getLatitudeDegrees", "()D");
method_correctionPlaneLngDeg = env->GetMethodID(refPlaneClass, "getLongitudeDegrees", "()D");
method_correctionPlaneAltDeg = env->GetMethodID(refPlaneClass, "getAltitudeMeters", "()D");
method_correctionPlaneAzimDeg = env->GetMethodID(refPlaneClass, "getAzimuthDegrees", "()D");
+
+ jclass excessPathInfoClass = env->FindClass("android/location/GnssExcessPathInfo");
+ method_excessPathInfoFlags = env->GetMethodID(excessPathInfoClass, "getFlags", "()I");
+ method_excessPathInfoEpl =
+ env->GetMethodID(excessPathInfoClass, "getExcessPathLengthMeters", "()F");
+ method_excessPathInfoEplUnc =
+ env->GetMethodID(excessPathInfoClass, "getExcessPathLengthUncertaintyMeters", "()F");
+ method_excessPathInfoRefPlane = env->GetMethodID(excessPathInfoClass, "getReflectingPlane",
+ "()Landroid/location/GnssReflectingPlane;");
+ method_excessPathInfoAttenuation =
+ env->GetMethodID(excessPathInfoClass, "getAttenuationDb", "()F");
}
template <>
@@ -324,7 +347,8 @@ jboolean MeasurementCorrectionsIface_V1_1::setCallback(
SingleSatCorrection_V1_0
MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
JNIEnv* env, jobject singleSatCorrectionObj) {
- jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+ uint16_t corrFlags = static_cast<uint16_t>(
+ env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
jfloat carrierFreqHz =
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -332,14 +356,16 @@ MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
- uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
ReflectingPlane_V1_0 reflectingPlane;
- if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0)
- MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_V1_0>(env,
- singleSatCorrectionObj,
+ if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0) {
+ jobject reflectingPlaneObj =
+ env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
+ MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_V1_0>(env,
+ reflectingPlaneObj,
reflectingPlane);
-
+ env->DeleteLocalRef(reflectingPlaneObj);
+ }
SingleSatCorrection_V1_0 singleSatCorrection = {
.singleSatCorrectionFlags = corrFlags,
.svid = static_cast<uint16_t>(satId),
@@ -349,13 +375,14 @@ MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
.excessPathLengthUncertaintyMeters = eplUncMeters,
.reflectingPlane = reflectingPlane,
};
-
return singleSatCorrection;
}
SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl(
JNIEnv* env, jobject singleSatCorrectionObj) {
- jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+ int32_t corrFlags = static_cast<int32_t>(
+ env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
+ jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
jfloat carrierFreqHz =
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -363,15 +390,10 @@ SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
- int32_t corrFlags = static_cast<int32_t>(correctionFlags);
-
- ReflectingPlane_Aidl reflectingPlane;
- if ((corrFlags & SingleSatCorrection_Aidl::SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE) != 0)
- MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_Aidl>(env,
- singleSatCorrectionObj,
- reflectingPlane);
-
- jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+ jfloat attenuationDb =
+ env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatAttenuation);
+ std::vector<ExcessPathInfo> excessPathInfos =
+ MeasurementCorrectionsUtil::getExcessPathInfoList(env, singleSatCorrectionObj);
SingleSatCorrection_Aidl singleSatCorrection;
singleSatCorrection.singleSatCorrectionFlags = corrFlags;
@@ -379,9 +401,10 @@ SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl
singleSatCorrection.svid = static_cast<int32_t>(satId);
singleSatCorrection.carrierFrequencyHz = carrierFreqHz;
singleSatCorrection.probSatIsLos = probSatIsLos;
- singleSatCorrection.excessPathLengthMeters = eplMeters;
- singleSatCorrection.excessPathLengthUncertaintyMeters = eplUncMeters;
- singleSatCorrection.reflectingPlane = reflectingPlane;
+ singleSatCorrection.combinedExcessPathLengthMeters = eplMeters;
+ singleSatCorrection.combinedExcessPathLengthUncertaintyMeters = eplUncMeters;
+ singleSatCorrection.combinedAttenuationDb = attenuationDb;
+ singleSatCorrection.excessPathInfos = excessPathInfos;
return singleSatCorrection;
}
@@ -391,8 +414,7 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_1_0(
hardware::hidl_vec<SingleSatCorrection_V1_0>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
-
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_V1_0 singleSatCorrection =
getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
@@ -410,7 +432,7 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_1_1(
hardware::hidl_vec<SingleSatCorrection_V1_1>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_V1_0 singleSatCorrection_1_0 =
getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
@@ -431,7 +453,7 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_Aidl(
JNIEnv* env, jobject singleSatCorrectionList, std::vector<SingleSatCorrection_Aidl>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_Aidl singleSatCorrection_Aidl =
getSingleSatCorrection_Aidl(env, singleSatCorrectionObj);
@@ -441,4 +463,63 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_Aidl(
}
}
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_V1_0>(
+ ReflectingPlane_V1_0& reflectingPlane, double azimuthDegreeRefPlane) {
+ reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
+}
+
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_Aidl>(
+ ReflectingPlane_Aidl& reflectingPlane, double azimuthDegreeRefPlane) {
+ reflectingPlane.reflectingPlaneAzimuthDegrees = azimuthDegreeRefPlane;
+}
+
+std::vector<ExcessPathInfo> MeasurementCorrectionsUtil::getExcessPathInfoList(
+ JNIEnv* env, jobject singleSatCorrectionObj) {
+ jobject excessPathInfoListObj =
+ env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatExcessPathInfoList);
+
+ int len = env->CallIntMethod(excessPathInfoListObj, method_listSize);
+ std::vector<ExcessPathInfo> list(len);
+ for (int i = 0; i < len; ++i) {
+ jobject excessPathInfoObj = env->CallObjectMethod(excessPathInfoListObj, method_listGet, i);
+ list[i] = getExcessPathInfo(env, excessPathInfoObj);
+ env->DeleteLocalRef(excessPathInfoObj);
+ }
+ env->DeleteLocalRef(excessPathInfoListObj);
+ return list;
+}
+
+ExcessPathInfo MeasurementCorrectionsUtil::getExcessPathInfo(JNIEnv* env,
+ jobject excessPathInfoObj) {
+ ExcessPathInfo excessPathInfo;
+ jint flags = env->CallIntMethod(excessPathInfoObj, method_excessPathInfoFlags);
+ excessPathInfo.excessPathInfoFlags = flags;
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH) != 0) {
+ jfloat epl = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEpl);
+ excessPathInfo.excessPathLengthMeters = epl;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC) != 0) {
+ jfloat eplUnc = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEplUnc);
+ excessPathInfo.excessPathLengthUncertaintyMeters = eplUnc;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_REFLECTING_PLANE) != 0) {
+ ReflectingPlane_Aidl reflectingPlane;
+ jobject reflectingPlaneObj =
+ env->CallObjectMethod(excessPathInfoObj, method_excessPathInfoRefPlane);
+ MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_Aidl>(env,
+ reflectingPlaneObj,
+ reflectingPlane);
+ env->DeleteLocalRef(reflectingPlaneObj);
+ excessPathInfo.reflectingPlane = reflectingPlane;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_ATTENUATION) != 0) {
+ jfloat attenuation =
+ env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoAttenuation);
+ excessPathInfo.attenuationDb = attenuation;
+ }
+ return excessPathInfo;
+}
+
} // namespace android::gnss
diff --git a/services/core/jni/gnss/MeasurementCorrections.h b/services/core/jni/gnss/MeasurementCorrections.h
index a2e602714326..598ad48d6ac1 100644
--- a/services/core/jni/gnss/MeasurementCorrections.h
+++ b/services/core/jni/gnss/MeasurementCorrections.h
@@ -43,7 +43,7 @@ extern jmethodID method_correctionsHasEnvironmentBearing;
extern jmethodID method_correctionsGetEnvironmentBearingDegrees;
extern jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
extern jmethodID method_listSize;
-extern jmethodID method_correctionListGet;
+extern jmethodID method_listGet;
extern jmethodID method_correctionSatFlags;
extern jmethodID method_correctionSatConstType;
extern jmethodID method_correctionSatId;
@@ -52,6 +52,7 @@ extern jmethodID method_correctionSatIsLosProb;
extern jmethodID method_correctionSatEpl;
extern jmethodID method_correctionSatEplUnc;
extern jmethodID method_correctionSatRefPlane;
+extern jmethodID method_correctionSatExcessPathInfos;
extern jmethodID method_correctionPlaneLatDeg;
extern jmethodID method_correctionPlaneLngDeg;
extern jmethodID method_correctionPlaneAltDeg;
@@ -130,14 +131,20 @@ struct MeasurementCorrectionsUtil {
static bool translateMeasurementCorrections(JNIEnv* env, jobject correctionsObj,
T& corrections);
template <class T>
- static void getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj, T& reflectingPlane);
+ static void setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj, T& reflectingPlane);
+ template <class T>
+ static void setReflectingPlaneAzimuthDegrees(T& reflectingPlane, double azimuthDegreeRefPlane);
+
+ static std::vector<
+ android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo>
+ getExcessPathInfoList(JNIEnv* env, jobject correctionsObj);
+ static android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo
+ getExcessPathInfo(JNIEnv* env, jobject correctionsObj);
};
template <class T>
-void MeasurementCorrectionsUtil::getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj,
+void MeasurementCorrectionsUtil::setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj,
T& reflectingPlane) {
- jobject reflectingPlaneObj =
- env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
jdouble latitudeDegreesRefPlane =
env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLatDeg);
jdouble longitudeDegreesRefPlane =
@@ -149,8 +156,7 @@ void MeasurementCorrectionsUtil::getReflectingPlane(JNIEnv* env, jobject singleS
reflectingPlane.latitudeDegrees = latitudeDegreesRefPlane;
reflectingPlane.longitudeDegrees = longitudeDegreesRefPlane;
reflectingPlane.altitudeMeters = altitudeDegreesRefPlane;
- reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
- env->DeleteLocalRef(reflectingPlaneObj);
+ setReflectingPlaneAzimuthDegrees<T>(reflectingPlane, azimuthDegreeRefPlane);
}
} // namespace android::gnss
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 2f5ab0b31332..48c40523e9c2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -1227,5 +1227,12 @@ class ActiveAdmin {
pw.print("mSsidDenylist=");
pw.println(mSsidDenylist);
+
+ if (mFactoryResetProtectionPolicy != null) {
+ pw.println("mFactoryResetProtectionPolicy:");
+ pw.increaseIndent();
+ mFactoryResetProtectionPolicy.dump(pw);
+ pw.decreaseIndent();
+ }
}
}
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..3b82660b75a4 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;
@@ -17808,6 +17810,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 +18713,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 +18741,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 +18755,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 +18777,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/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 784f732ba3b1..8d6269c93764 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -118,6 +118,7 @@ public class LocalDisplayAdapterTest {
LocalServices.removeServiceForTest(LightsManager.class);
LocalServices.addService(LightsManager.class, mMockedLightsManager);
mInjector = new Injector();
+ when(mSurfaceControlProxy.getBootDisplayModeSupport()).thenReturn(true);
mAdapter = new LocalDisplayAdapter(mMockedSyncRoot, mMockedContext, mHandler,
mListener, mInjector);
spyOn(mAdapter);
@@ -904,7 +905,6 @@ public class LocalDisplayAdapterTest {
.thenReturn(display.dynamicInfo);
when(mSurfaceControlProxy.getDesiredDisplayModeSpecs(display.token))
.thenReturn(display.desiredDisplayModeSpecs);
- when(mSurfaceControlProxy.getBootDisplayModeSupport()).thenReturn(true);
}
private void updateAvailableDisplays() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
index 6f503c7dd941..444db9128662 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
@@ -19,7 +19,9 @@ package com.android.server.pm;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
@@ -36,23 +38,21 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.os.HandlerThread;
import android.os.PowerManager;
-import android.util.ArraySet;
import com.android.server.LocalServices;
import com.android.server.PinnerService;
import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.DexoptOptions;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
@@ -66,9 +66,8 @@ public final class BackgroundDexOptServiceUnitTest {
private static final long TEST_WAIT_TIMEOUT_MS = 10_000;
- private static final ArraySet<String> DEFAULT_PACKAGE_LIST = new ArraySet<>(
- Arrays.asList("aaa", "bbb"));
- private static final ArraySet<String> EMPTY_PACKAGE_LIST = new ArraySet<>();
+ private static final List<String> DEFAULT_PACKAGE_LIST = List.of("aaa", "bbb");
+ private static final List<String> EMPTY_PACKAGE_LIST = List.of();
@Mock
private Context mContext;
@@ -116,9 +115,11 @@ public final class BackgroundDexOptServiceUnitTest {
when(mInjector.getDataDirStorageLowBytes()).thenReturn(STORAGE_LOW_BYTES);
when(mInjector.getDexOptThermalCutoff()).thenReturn(PowerManager.THERMAL_STATUS_CRITICAL);
when(mInjector.getCurrentThermalStatus()).thenReturn(PowerManager.THERMAL_STATUS_NONE);
+ when(mInjector.supportSecondaryDex()).thenReturn(true);
when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(DEFAULT_PACKAGE_LIST);
when(mDexOptHelper.performDexOptWithStatus(any())).thenReturn(
PackageDexOptimizer.DEX_OPT_PERFORMED);
+ when(mDexOptHelper.performDexOpt(any())).thenReturn(true);
mService = new BackgroundDexOptService(mInjector);
}
@@ -418,26 +419,16 @@ public final class BackgroundDexOptServiceUnitTest {
verifyPerformDexOpt(DEFAULT_PACKAGE_LIST, totalJobRuns);
}
- private void verifyPerformDexOpt(ArraySet<String> pkgs, int expectedRuns) {
- ArgumentCaptor<DexoptOptions> dexOptOptions = ArgumentCaptor.forClass(DexoptOptions.class);
- verify(mDexOptHelper, atLeastOnce()).performDexOptWithStatus(dexOptOptions.capture());
- HashMap<String, Integer> primaryPkgs = new HashMap<>(); // K: pkg, V: dexopt runs left
- for (String pkg : pkgs) {
- primaryPkgs.put(pkg, expectedRuns);
- }
-
- for (DexoptOptions opt : dexOptOptions.getAllValues()) {
- assertThat(pkgs).contains(opt.getPackageName());
- assertThat(opt.isDexoptOnlySecondaryDex()).isFalse();
- Integer count = primaryPkgs.get(opt.getPackageName());
- assertThat(count).isNotNull();
- if (count == 1) {
- primaryPkgs.remove(opt.getPackageName());
- } else {
- primaryPkgs.put(opt.getPackageName(), count - 1);
+ private void verifyPerformDexOpt(List<String> pkgs, int expectedRuns) {
+ InOrder inOrder = inOrder(mDexOptHelper);
+ for (int i = 0; i < expectedRuns; i++) {
+ for (String pkg : pkgs) {
+ inOrder.verify(mDexOptHelper, times(1)).performDexOptWithStatus(argThat((option) ->
+ option.getPackageName().equals(pkg) && !option.isDexoptOnlySecondaryDex()));
+ inOrder.verify(mDexOptHelper, times(1)).performDexOpt(argThat((option) ->
+ option.getPackageName().equals(pkg) && option.isDexoptOnlySecondaryDex()));
}
}
- assertThat(primaryPkgs).isEmpty();
}
private static class StartAndWaitThread extends Thread {
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
new file mode 100644
index 000000000000..52cd29cabb94
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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.server.utils;
+
+import static android.os.Trace.TRACE_TAG_APP;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.contains;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.matches;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+
+import android.os.Trace;
+import android.util.Slog;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.MockedVoidMethod;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link TimingsTraceAndSlog}.
+ *
+ * <p>Usage: {@code atest FrameworksMockingServicesTests:TimingsTraceAndSlogTest}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimingsTraceAndSlogTest {
+
+ private static final String TAG = "TEST";
+
+ private MockitoSession mSession;
+
+ @Before
+ public final void startMockSession() {
+ mSession = mockitoSession()
+ .spyStatic(Slog.class)
+ .spyStatic(Trace.class)
+ .startMocking();
+ }
+
+ @After
+ public final void finishMockSession() {
+ mSession.finishMocking();
+ }
+
+ @Test
+ public void testDifferentThreads() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ // Should be able to log on the same thread
+ log.traceBegin("test");
+ log.traceEnd();
+ final List<String> errors = new ArrayList<>();
+ // Calling from a different thread should fail
+ Thread t = new Thread(() -> {
+ try {
+ log.traceBegin("test");
+ errors.add("traceBegin should fail on a different thread");
+ } catch (IllegalStateException expected) {
+ }
+ try {
+ log.traceEnd();
+ errors.add("traceEnd should fail on a different thread");
+ } catch (IllegalStateException expected) {
+ }
+ // Verify that creating a new log will work
+ TimingsTraceAndSlog log2 = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log2.traceBegin("test");
+ log2.traceEnd();
+
+ });
+ t.start();
+ t.join();
+ assertThat(errors).isEmpty();
+ }
+
+ @Test
+ public void testGetUnfinishedTracesForDebug() {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+
+ log.traceBegin("One");
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+ log.traceBegin("Two");
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One", "Two").inOrder();
+
+ log.traceEnd();
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+ log.traceEnd();
+ assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+ }
+
+ @Test
+ public void testLogDuration() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.logDuration("logro", 42);
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
+ }
+
+ @Test
+ public void testOneLevel() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceBegin("test");
+ log.traceEnd();
+
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
+ }
+
+ @Test
+ public void testMultipleLevels() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceBegin("L1");
+ log.traceBegin("L2");
+ log.traceEnd();
+ log.traceEnd();
+
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L1"));
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
+
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ }
+
+ @Test
+ public void testEndNoBegin() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceEnd();
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), anyString()), never());
+ verify((MockedVoidMethod) () -> Slog.w(TAG, "traceEnd called more times than traceBegin"));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
new file mode 100644
index 000000000000..26a83a23de33
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.server.display;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManagerInternal;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ColorFadeTest {
+ private static final int DISPLAY_ID = 123;
+
+ private Context mContext;
+
+ @Mock private DisplayManagerInternal mDisplayManagerInternalMock;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+ mContext = getInstrumentation().getTargetContext();
+ }
+
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+ }
+
+ @Test
+ public void testPrepareColorFadeForInvalidDisplay() {
+ when(mDisplayManagerInternalMock.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(null);
+ ColorFade colorFade = new ColorFade(DISPLAY_ID);
+ assertFalse(colorFade.prepare(mContext, ColorFade.MODE_FADE));
+ }
+
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+
+}
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/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index f9aa4b17bc2c..9902e83c3648 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -500,6 +500,23 @@ public class ActivityStarterTests extends WindowTestsBase {
return Pair.create(splitPrimaryActivity, splitSecondActivity);
}
+ @Test
+ public void testMoveVisibleTaskToFront() {
+ final ActivityRecord activity = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true).build().getTopMostActivity();
+ final ActivityRecord translucentActivity = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true).build().getTopMostActivity();
+ assertTrue(activity.mVisibleRequested);
+
+ final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+ false /* mockGetRootTask */);
+ starter.getIntent().setComponent(activity.mActivityComponent);
+ final int result = starter.setReason("testMoveVisibleTaskToFront").execute();
+
+ assertEquals(START_TASK_TO_FRONT, result);
+ assertEquals(1, activity.compareTo(translucentActivity));
+ }
+
/**
* Tests activity is cleaned up properly in a task mode violation.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 50eefa066a45..c5117bb83976 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -19,12 +19,12 @@ package com.android.server.wm;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
-import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ContentRecorder.KEY_RECORD_TASK_FEATURE;
import static com.google.common.truth.Truth.assertThat;
@@ -40,17 +40,22 @@ import android.hardware.display.VirtualDisplay;
import android.os.Binder;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
import android.util.DisplayMetrics;
import android.view.ContentRecordingSession;
import android.view.Surface;
import android.view.SurfaceControl;
+import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.CountDownLatch;
+
/**
* Tests for the {@link ContentRecorder} class.
*
@@ -62,17 +67,18 @@ import org.junit.runner.RunWith;
@RunWith(WindowTestRunner.class)
public class ContentRecorderTests extends WindowTestsBase {
private static final IBinder TEST_TOKEN = new RecordingTestToken();
- private final ContentRecordingSession mDefaultSession =
+ private static IBinder sTaskWindowContainerToken;
+ private final ContentRecordingSession mDisplaySession =
ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+ private ContentRecordingSession mTaskSession;
private static Point sSurfaceSize;
private ContentRecorder mContentRecorder;
private SurfaceControl mRecordedSurface;
+ // Handle feature flag.
+ private ConfigListener mConfigListener;
+ private CountDownLatch mLatch;
@Before public void setUp() {
- // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
- // mirror.
- setUpDefaultTaskDisplayAreaWindowToken();
-
// GIVEN SurfaceControl can successfully mirror the provided surface.
sSurfaceSize = new Point(
mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
@@ -84,12 +90,32 @@ public class ContentRecorderTests extends WindowTestsBase {
sSurfaceSize.x, sSurfaceSize.y,
DisplayMetrics.DENSITY_140, new Surface(), VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
final int displayId = virtualDisplay.getDisplay().getDisplayId();
- mDefaultSession.setDisplayId(displayId);
-
mWm.mRoot.onDisplayAdded(displayId);
- final DisplayContent mVirtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
- mContentRecorder = new ContentRecorder(mVirtualDisplayContent);
- spyOn(mVirtualDisplayContent);
+ final DisplayContent virtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
+ mContentRecorder = new ContentRecorder(virtualDisplayContent);
+ spyOn(virtualDisplayContent);
+
+ // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+ // record.
+ setUpDefaultTaskDisplayAreaWindowToken();
+ mDisplaySession.setDisplayId(displayId);
+
+ // GIVEN there is a window token associated with a task to record.
+ sTaskWindowContainerToken = setUpTaskWindowContainerToken(virtualDisplayContent);
+ mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
+ mTaskSession.setDisplayId(displayId);
+
+ mConfigListener = new ConfigListener();
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ mContext.getMainExecutor(), mConfigListener);
+ mLatch = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+ "true", true);
+ }
+
+ @After
+ public void teardown() {
+ DeviceConfig.removeOnPropertiesChangedListener(mConfigListener);
}
@Test
@@ -102,37 +128,79 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testUpdateRecording_display() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
}
@Test
- public void testUpdateRecording_task() {
- mDefaultSession.setContentToRecord(RECORD_CONTENT_TASK);
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ public void testUpdateRecording_display_nullToken() {
+ ContentRecordingSession session = ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+ session.setDisplayId(mDisplaySession.getDisplayId());
+ session.setTokenToRecord(null);
+ mContentRecorder.setContentRecordingSession(session);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
}
@Test
- public void testUpdateRecording_wasPaused() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ public void testUpdateRecording_display_noWindowContainer() {
+ doReturn(null).when(
+ mWm.mWindowContextListenerController).getContainer(any());
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
- mContentRecorder.pauseRecording();
+ @Test
+ public void testUpdateRecording_task_featureDisabled() {
+ mLatch = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+ "false", false);
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
+
+ @Test
+ public void testUpdateRecording_task_featureEnabled() {
+ // Feature already enabled; don't need to again.
+ mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
}
@Test
- public void testUpdateRecording_wasStopped() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ public void testUpdateRecording_task_nullToken() {
+ ContentRecordingSession session = ContentRecordingSession.createTaskSession(
+ sTaskWindowContainerToken);
+ session.setDisplayId(mDisplaySession.getDisplayId());
+ session.setTokenToRecord(null);
+ mContentRecorder.setContentRecordingSession(session);
mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+ }
- mContentRecorder.remove();
+ @Test
+ public void testUpdateRecording_task_noWindowContainer() {
+ // Use the window container token of the DisplayContent, rather than task.
+ ContentRecordingSession invalidTaskSession = ContentRecordingSession.createTaskSession(
+ new WindowContainer.RemoteToken(mDisplayContent));
+ mContentRecorder.setContentRecordingSession(invalidTaskSession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+ }
+
+ @Test
+ public void testUpdateRecording_wasPaused() {
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+
+ mContentRecorder.pauseRecording();
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
}
@Test
@@ -146,7 +214,7 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testOnConfigurationChanged_resizesSurface() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
@@ -158,7 +226,7 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testPauseRecording_pausesRecording() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.pauseRecording();
@@ -173,7 +241,7 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testRemove_stopsRecording() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.remove();
@@ -188,8 +256,9 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testUpdateMirroredSurface_capturedAreaResized() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
// WHEN attempting to mirror on the virtual display, and the captured content is resized.
float xScale = 0.7f;
@@ -197,13 +266,14 @@ public class ContentRecorderTests extends WindowTestsBase {
Rect displayAreaBounds = new Rect(0, 0, Math.round(sSurfaceSize.x * xScale),
Math.round(sSurfaceSize.y * yScale));
mContentRecorder.updateMirroredSurface(mTransaction, displayAreaBounds, sSurfaceSize);
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
// THEN content in the captured DisplayArea is scaled to fit the surface size.
verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, 1.0f / yScale, 0, 0,
1.0f / yScale);
// THEN captured content is positioned in the centre of the output surface.
- float scaledWidth = displayAreaBounds.width() / xScale;
- float xInset = (sSurfaceSize.x - scaledWidth) / 2;
+ int scaledWidth = Math.round((float) displayAreaBounds.width() / xScale);
+ int xInset = (sSurfaceSize.x - scaledWidth) / 2;
verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0);
}
@@ -222,6 +292,18 @@ public class ContentRecorderTests extends WindowTestsBase {
}
/**
+ * Creates a {@link android.window.WindowContainerToken} associated with a task, in order for
+ * that task to be recorded.
+ */
+ private IBinder setUpTaskWindowContainerToken(DisplayContent displayContent) {
+ final Task rootTask = createTask(displayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+ // Ensure the task is not empty.
+ createActivityRecord(displayContent, task);
+ return task.getTaskInfo().token.asBinder();
+ }
+
+ /**
* SurfaceControl successfully creates a mirrored surface of the given size.
*/
private SurfaceControl surfaceControlMirrors(Point surfaceSize) {
@@ -236,4 +318,13 @@ public class ContentRecorderTests extends WindowTestsBase {
anyInt());
return mirroredSurface;
}
+
+ private class ConfigListener implements DeviceConfig.OnPropertiesChangedListener {
+ @Override
+ public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+ if (mLatch != null && properties.getKeyset().contains(KEY_RECORD_TASK_FEATURE)) {
+ mLatch.countDown();
+ }
+ }
+ }
}
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(