summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/appsearch/framework/api/current.txt3
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java33
-rw-r--r--apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java2
-rw-r--r--core/api/current.txt17
-rw-r--r--core/api/system-current.txt18
-rw-r--r--core/api/test-current.txt17
-rw-r--r--core/java/android/app/AppOpsManager.java2
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java3
-rw-r--r--core/java/android/content/pm/ActivityInfo.java11
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedActivityUtils.java5
-rw-r--r--core/java/android/net/netstats/provider/NetworkStatsProvider.java7
-rw-r--r--core/java/android/os/BatteryUsageStatsQuery.java24
-rw-r--r--core/java/android/permission/PermGroupUsage.java47
-rw-r--r--core/java/android/permission/PermissionManager.java2
-rw-r--r--core/java/android/permission/PermissionUsageHelper.java11
-rw-r--r--core/java/android/service/autofill/AutofillService.java37
-rw-r--r--core/java/android/service/autofill/IAutoFillService.aidl1
-rw-r--r--core/java/android/service/autofill/SavedDatasetsInfo.java186
-rw-r--r--core/java/android/service/autofill/SavedDatasetsInfoCallback.java72
-rw-r--r--core/java/android/service/autofill/SavedDatasetsInfoCallbackImpl.java93
-rw-r--r--core/java/android/view/SurfaceView.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java2
-rw-r--r--core/java/com/android/internal/os/BatteryUsageStatsProvider.java40
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/values/attrs_manifest.xml7
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--core/res/res/values/strings.xml9
-rw-r--r--core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java2
-rw-r--r--core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java1
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java18
-rw-r--r--graphics/java/android/graphics/Typeface.java27
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java6
-rw-r--r--graphics/java/android/graphics/drawable/RippleShader.java23
-rw-r--r--keystore/java/android/security/AndroidKeyStoreMaintenance.java14
-rw-r--r--keystore/java/android/security/KeyStore.java1
-rw-r--r--keystore/java/android/security/KeyStore2.java5
-rw-r--r--libs/hwui/hwui/ImageDecoder.cpp11
-rw-r--r--libs/hwui/hwui/ImageDecoder.h4
-rw-r--r--libs/hwui/jni/ImageDecoder.cpp3
-rw-r--r--packages/Connectivity/framework/api/system-current.txt5
-rw-r--r--packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl2
-rw-r--r--packages/Connectivity/framework/src/android/net/IQosCallback.aidl3
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkAgent.java31
-rw-r--r--packages/Connectivity/framework/src/android/net/QosCallbackConnection.java20
-rw-r--r--packages/Connectivity/framework/src/android/net/QosSession.java6
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp1
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml60
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/collapsing_toolbar_base_layout.xml50
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/toolbar_base_layout.xml36
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java12
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java78
-rw-r--r--packages/SystemUI/res/values/attrs.xml1
-rw-r--r--packages/SystemUI/res/values/config.xml8
-rw-r--r--packages/SystemUI/res/values/strings.xml6
-rw-r--r--packages/SystemUI/res/values/styles.xml2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java121
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java113
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellConcurrencyModule.java163
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java312
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java52
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java21
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java6
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java7
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java9
-rw-r--r--services/core/java/com/android/server/am/UserController.java13
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java9
-rw-r--r--services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java17
-rw-r--r--services/core/java/com/android/server/connectivity/QosCallbackTracker.java23
-rw-r--r--services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java13
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java89
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java11
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java34
-rw-r--r--services/incremental/IncrementalService.cpp44
-rw-r--r--services/incremental/IncrementalService.h2
-rw-r--r--services/incremental/ServiceWrappers.cpp23
-rw-r--r--services/incremental/ServiceWrappers.h8
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp12
-rw-r--r--services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java30
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UserControllerTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java67
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java84
-rw-r--r--telephony/java/android/telephony/data/NrQos.java12
-rw-r--r--telephony/java/android/telephony/data/NrQosSessionAttributes.aidl19
-rw-r--r--telephony/java/android/telephony/data/NrQosSessionAttributes.java256
-rw-r--r--tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java6
-rw-r--r--tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java6
-rw-r--r--tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java6
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleDataClass.java130
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java6
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java18
-rw-r--r--tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java6
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java33
-rw-r--r--tools/codegen/src/com/android/codegen/FieldInfo.kt3
-rw-r--r--tools/codegen/src/com/android/codegen/SharedConstants.kt2
99 files changed, 2410 insertions, 511 deletions
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index a3e05dc7cd85..47cf17cb1d4c 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -149,7 +149,8 @@ package android.app.appsearch {
method public void remove(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
method public void reportUsage(@NonNull android.app.appsearch.ReportUsageRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec);
- method public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.SetSchemaResponse>>);
+ method @Deprecated public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.SetSchemaResponse>>);
+ method public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.SetSchemaResponse>>);
}
public interface BatchResultCallback<KeyType, ValueType> {
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index ce4aad1f0c1e..bf733ed77442 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -104,6 +104,18 @@ public final class AppSearchSession implements Closeable {
}
/**
+ * TODO(b/181887768): This method exists only for dogfooder transition and must be removed.
+ * @deprecated This method exists only for dogfooder transition and must be removed.
+ */
+ @Deprecated
+ public void setSchema(
+ @NonNull SetSchemaRequest request,
+ @NonNull @CallbackExecutor Executor callbackExecutor,
+ @NonNull Consumer<AppSearchResult<SetSchemaResponse>> callback) {
+ setSchema(request, callbackExecutor, callbackExecutor, callback);
+ }
+
+ /**
* Sets the schema that represents the organizational structure of data within the AppSearch
* database.
*
@@ -113,7 +125,9 @@ public final class AppSearchSession implements Closeable {
* no-op call.
*
* @param request the schema to set or update the AppSearch database to.
- * @param executor Executor on which to invoke the callback.
+ * @param workExecutor Executor on which to schedule heavy client-side background work such as
+ * transforming documents.
+ * @param callbackExecutor Executor on which to invoke the callback.
* @param callback Callback to receive errors resulting from setting the schema. If the
* operation succeeds, the callback will be invoked with {@code null}.
*/
@@ -121,10 +135,12 @@ public final class AppSearchSession implements Closeable {
// exposed.
public void setSchema(
@NonNull SetSchemaRequest request,
- @NonNull @CallbackExecutor Executor executor,
+ @NonNull Executor workExecutor,
+ @NonNull @CallbackExecutor Executor callbackExecutor,
@NonNull Consumer<AppSearchResult<SetSchemaResponse>> callback) {
Objects.requireNonNull(request);
- Objects.requireNonNull(executor);
+ Objects.requireNonNull(workExecutor);
+ Objects.requireNonNull(callbackExecutor);
Objects.requireNonNull(callback);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
List<Bundle> schemaBundles = new ArrayList<>(request.getSchemas().size());
@@ -153,10 +169,12 @@ public final class AppSearchSession implements Closeable {
request.getVersion(),
new IAppSearchResultCallback.Stub() {
public void onResult(AppSearchResult result) {
- executor.execute(() -> {
+ callbackExecutor.execute(() -> {
if (result.isSuccess()) {
callback.accept(
// TODO(b/177266929) implement Migration in platform.
+ // TODO(b/183177268): once migration is implemented, run
+ // it on workExecutor.
AppSearchResult.newSuccessfulResult(
new SetSchemaResponse.Builder().build()));
} else {
@@ -332,8 +350,7 @@ public final class AppSearchSession implements Closeable {
// Translate successful results
for (Map.Entry<String, Bundle> bundleEntry :
- (Set<Map.Entry<String, Bundle>>)
- result.getSuccesses().entrySet()) {
+ ((Map<String, Bundle>) result.getSuccesses()).entrySet()) {
GenericDocument document;
try {
document = new GenericDocument(bundleEntry.getValue());
@@ -352,8 +369,8 @@ public final class AppSearchSession implements Closeable {
// Translate failed results
for (Map.Entry<String, AppSearchResult<Bundle>> bundleEntry :
- (Set<Map.Entry<String, AppSearchResult<Bundle>>>)
- result.getFailures().entrySet()) {
+ ((Map<String, AppSearchResult<Bundle>>)
+ result.getFailures()).entrySet()) {
documentResultBuilder.setFailure(
bundleEntry.getKey(),
bundleEntry.getValue().getResultCode(),
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
index bc3064155d34..f0de4962ad3c 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
@@ -89,7 +89,7 @@ public class AppSearchSessionShimImpl implements AppSearchSessionShim {
@NonNull
public ListenableFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest request) {
SettableFuture<AppSearchResult<SetSchemaResponse>> future = SettableFuture.create();
- mAppSearchSession.setSchema(request, mExecutor, future::set);
+ mAppSearchSession.setSchema(request, mExecutor, mExecutor, future::set);
return Futures.transformAsync(future, this::transformResult, mExecutor);
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 11f521565e9e..6abb3f7d8c1a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -37485,6 +37485,7 @@ package android.service.autofill {
method public void onDisconnected();
method public abstract void onFillRequest(@NonNull android.service.autofill.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback);
method public abstract void onSaveRequest(@NonNull android.service.autofill.SaveRequest, @NonNull android.service.autofill.SaveCallback);
+ method public void onSavedDatasetsInfoRequest(@NonNull android.service.autofill.SavedDatasetsInfoCallback);
field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
field public static final String SERVICE_META_DATA = "android.autofill";
}
@@ -37760,6 +37761,22 @@ package android.service.autofill {
field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
}
+ public final class SavedDatasetsInfo {
+ ctor public SavedDatasetsInfo(@NonNull String, @IntRange(from=0) int);
+ method @IntRange(from=0) public int getCount();
+ method @NonNull public String getType();
+ field public static final String TYPE_OTHER = "other";
+ field public static final String TYPE_PASSWORDS = "passwords";
+ }
+
+ public interface SavedDatasetsInfoCallback {
+ method public void onError(int);
+ method public void onSuccess(@NonNull java.util.Set<android.service.autofill.SavedDatasetsInfo>);
+ field public static final int ERROR_NEEDS_USER_ACTION = 2; // 0x2
+ field public static final int ERROR_OTHER = 0; // 0x0
+ field public static final int ERROR_UNSUPPORTED = 1; // 0x1
+ }
+
public final class TextValueSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
ctor public TextValueSanitizer(@NonNull java.util.regex.Pattern, @NonNull String);
method public int describeContents();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 55dd8b2d81b4..2094e981f68e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -92,6 +92,7 @@ package android {
field public static final String CREATE_USERS = "android.permission.CREATE_USERS";
field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
field public static final String DEVICE_POWER = "android.permission.DEVICE_POWER";
+ field public static final String DISABLE_SYSTEM_SOUND_EFFECTS = "android.permission.DISABLE_SYSTEM_SOUND_EFFECTS";
field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
field public static final String DOMAIN_VERIFICATION_AGENT = "android.permission.DOMAIN_VERIFICATION_AGENT";
field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
@@ -311,6 +312,7 @@ package android {
field public static final int hotwordDetectionService = 16844326; // 0x1010626
field public static final int isVrOnly = 16844152; // 0x1010578
field public static final int minExtensionVersion = 16844305; // 0x1010611
+ field public static final int playHomeTransitionSound = 16844358; // 0x1010646
field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
field public static final int sdkVersion = 16844304; // 0x1010610
@@ -7575,9 +7577,11 @@ package android.net.netstats.provider {
method public void notifyAlertReached();
method public void notifyLimitReached();
method public void notifyStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats);
+ method public void notifyWarningReached();
method public abstract void onRequestStatsUpdate(int);
method public abstract void onSetAlert(long);
method public abstract void onSetLimit(@NonNull String, long);
+ method public void onSetWarningAndLimit(@NonNull String, long, long);
field public static final int QUOTA_UNLIMITED = -1; // 0xffffffff
}
@@ -12301,6 +12305,20 @@ package android.telephony.data {
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.EpsBearerQosSessionAttributes> CREATOR;
}
+ public final class NrQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
+ method public int describeContents();
+ method public int get5Qi();
+ method public long getAveragingWindow();
+ method public long getGuaranteedDownlinkBitRate();
+ method public long getGuaranteedUplinkBitRate();
+ method public long getMaxDownlinkBitRate();
+ method public long getMaxUplinkBitRate();
+ method public int getQfi();
+ method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.NrQosSessionAttributes> CREATOR;
+ }
+
public abstract class QualifiedNetworksService extends android.app.Service {
ctor public QualifiedNetworksService();
method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 746a0b6f8e30..97ad48c96829 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -233,6 +233,8 @@ package android.app {
field public static final String KEY_FG_SERVICE_STATE_SETTLE_TIME = "fg_service_state_settle_time";
field public static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
field public static final String OPSTR_MANAGE_ONGOING_CALLS = "android:manage_ongoing_calls";
+ field public static final String OPSTR_PHONE_CALL_CAMERA = "android:phone_call_camera";
+ field public static final String OPSTR_PHONE_CALL_MICROPHONE = "android:phone_call_microphone";
field public static final String OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER = "android:use_icc_auth_with_device_identifier";
field public static final int OP_COARSE_LOCATION = 0; // 0x0
field public static final int OP_RECORD_AUDIO = 27; // 0x1b
@@ -1931,6 +1933,17 @@ package android.os.vibrator {
package android.permission {
+ public final class PermGroupUsage {
+ ctor public PermGroupUsage(@NonNull String, int, @NonNull String, long, boolean, boolean, @Nullable CharSequence);
+ method @Nullable public CharSequence getAttribution();
+ method public long getLastAccess();
+ method @NonNull public String getPackageName();
+ method @NonNull public String getPermGroupName();
+ method public int getUid();
+ method public boolean isActive();
+ method public boolean isPhoneCall();
+ }
+
public final class PermissionControllerManager {
method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void countPermissionApps(@NonNull java.util.List<java.lang.String>, int, @NonNull android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getAppPermissions(@NonNull String, @NonNull android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, @Nullable android.os.Handler);
@@ -1945,6 +1958,10 @@ package android.permission {
method public void onGetAppPermissions(@NonNull java.util.List<android.permission.RuntimePermissionPresentationInfo>);
}
+ public final class PermissionManager {
+ method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData();
+ }
+
}
package android.print {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index a6aa28effe00..7e4af1ad7952 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1561,12 +1561,14 @@ public class AppOpsManager {
*
* @hide
*/
+ @TestApi
public static final String OPSTR_PHONE_CALL_MICROPHONE = "android:phone_call_microphone";
/**
* Phone call is using camera
*
* @hide
*/
+ @TestApi
public static final String OPSTR_PHONE_CALL_CAMERA = "android:phone_call_camera";
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 117df02a2d7c..d3534f9bb3c7 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -872,8 +872,7 @@ public class DevicePolicyManager {
*
* The name is displayed only during provisioning.
*
- * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
- * or {@link #ACTION_PROVISION_FINANCED_DEVICE}
+ * <p>Use in an intent with action {@link #ACTION_PROVISION_FINANCED_DEVICE}
*
* @hide
*/
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index feb58a30e519..0952b3e1233c 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -550,9 +550,18 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
public static final int FLAG_INHERIT_SHOW_WHEN_LOCKED = 0x1;
/**
+ * Bit in {@link #privateFlags} indicating whether a home sound effect should be played if the
+ * home app moves to front after the activity with this flag set.
+ * Set from the {@link android.R.attr#playHomeTransitionSound} attribute.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_HOME_TRANSITION_SOUND = 0x2;
+
+ /**
* Options that have been set in the activity declaration in the manifest.
* These include:
- * {@link #FLAG_INHERIT_SHOW_WHEN_LOCKED}.
+ * {@link #FLAG_INHERIT_SHOW_WHEN_LOCKED},
+ * {@link #PRIVATE_FLAG_HOME_TRANSITION_SOUND}.
* @hide
*/
public int privateFlags;
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index d99c4109e5ad..ff6aaad09d09 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -149,7 +149,10 @@ public class ParsedActivityUtils {
| flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa)
| flag(ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING, R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, sa);
- activity.privateFlags |= flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa);
+ activity.privateFlags |= flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED,
+ R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa)
+ | flag(ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND,
+ R.styleable.AndroidManifestActivity_playHomeTransitionSound, true, sa);
activity.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, ActivityInfo.COLOR_MODE_DEFAULT);
activity.documentLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_documentLaunchMode, ActivityInfo.DOCUMENT_LAUNCH_NONE);
diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java
index 65b336ad6fce..23fc06927ef9 100644
--- a/core/java/android/net/netstats/provider/NetworkStatsProvider.java
+++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java
@@ -147,10 +147,7 @@ public abstract class NetworkStatsProvider {
/**
* Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached.
- *
- * @hide
*/
- // TODO: Expose as system API.
public void notifyWarningReached() {
try {
// Reuse the code path to notify warning reached with limit reached
@@ -198,7 +195,6 @@ public abstract class NetworkStatsProvider {
* @param quotaBytes the quota defined as the number of bytes, starting from zero and counting
* from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
*/
- // TODO: deprecate this once onSetWarningAndLimit is ready.
public abstract void onSetLimit(@NonNull String iface, long quotaBytes);
/**
@@ -217,10 +213,7 @@ public abstract class NetworkStatsProvider {
* there is no warning.
* @param limitBytes the limit defined as the number of bytes, starting from zero and counting
* from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
- *
- * @hide
*/
- // TODO: Expose as system API.
public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) {
// Backward compatibility for those who didn't override this function.
onSetLimit(iface, limitBytes);
diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java
index 9518bf197fa0..85861bc1d2aa 100644
--- a/core/java/android/os/BatteryUsageStatsQuery.java
+++ b/core/java/android/os/BatteryUsageStatsQuery.java
@@ -60,14 +60,18 @@ public final class BatteryUsageStatsQuery implements Parcelable {
*/
public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY = 2;
+ private static final long DEFAULT_MAX_STATS_AGE_MS = 5 * 60 * 1000;
+
private final int mFlags;
@NonNull
private final int[] mUserIds;
+ private final long mMaxStatsAgeMs;
private BatteryUsageStatsQuery(@NonNull Builder builder) {
mFlags = builder.mFlags;
mUserIds = builder.mUserIds != null ? builder.mUserIds.toArray()
: new int[]{UserHandle.USER_ALL};
+ mMaxStatsAgeMs = builder.mMaxStatsAgeMs;
}
@BatteryUsageStatsFlags
@@ -94,10 +98,19 @@ public final class BatteryUsageStatsQuery implements Parcelable {
return (mFlags & FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL) != 0;
}
+ /**
+ * Returns the client's tolerance for stale battery stats. The data is allowed to be up to
+ * this many milliseconds out-of-date.
+ */
+ public long getMaxStatsAge() {
+ return mMaxStatsAgeMs;
+ }
+
private BatteryUsageStatsQuery(Parcel in) {
mFlags = in.readInt();
mUserIds = new int[in.readInt()];
in.readIntArray(mUserIds);
+ mMaxStatsAgeMs = in.readLong();
}
@Override
@@ -105,6 +118,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
dest.writeInt(mFlags);
dest.writeInt(mUserIds.length);
dest.writeIntArray(mUserIds);
+ dest.writeLong(mMaxStatsAgeMs);
}
@Override
@@ -132,6 +146,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
public static final class Builder {
private int mFlags;
private IntArray mUserIds;
+ private long mMaxStatsAgeMs = DEFAULT_MAX_STATS_AGE_MS;
/**
* Builds a read-only BatteryUsageStatsQuery object.
@@ -170,5 +185,14 @@ public final class BatteryUsageStatsQuery implements Parcelable {
mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL;
return this;
}
+
+ /**
+ * Set the client's tolerance for stale battery stats. The data may be up to
+ * this many milliseconds out-of-date.
+ */
+ public Builder setMaxStatsAgeMs(long maxStatsAgeMs) {
+ mMaxStatsAgeMs = maxStatsAgeMs;
+ return this;
+ }
}
}
diff --git a/core/java/android/permission/PermGroupUsage.java b/core/java/android/permission/PermGroupUsage.java
index c94c0ffd4652..440d6f269646 100644
--- a/core/java/android/permission/PermGroupUsage.java
+++ b/core/java/android/permission/PermGroupUsage.java
@@ -18,6 +18,7 @@ package android.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
/**
* Represents the usage of a permission group by an app. Supports package name, user, permission
@@ -26,6 +27,7 @@ import android.annotation.Nullable;
*
* @hide
*/
+@TestApi
public final class PermGroupUsage {
private final String mPackageName;
@@ -36,7 +38,19 @@ public final class PermGroupUsage {
private final boolean mIsPhoneCall;
private final CharSequence mAttribution;
- PermGroupUsage(@NonNull String packageName, int uid,
+ /**
+ *
+ * @param packageName The package name of the using app
+ * @param uid The uid of the using app
+ * @param permGroupName The name of the permission group being used
+ * @param lastAccess The time of last access
+ * @param isActive Whether this is active
+ * @param isPhoneCall Whether this is a usage by the phone
+ * @param attribution An optional string attribution to show
+ * @hide
+ */
+ @TestApi
+ public PermGroupUsage(@NonNull String packageName, int uid,
@NonNull String permGroupName, long lastAccess, boolean isActive, boolean isPhoneCall,
@Nullable CharSequence attribution) {
this.mPackageName = packageName;
@@ -48,30 +62,58 @@ public final class PermGroupUsage {
this.mAttribution = attribution;
}
+ /**
+ * @hide
+ */
+ @TestApi
public @NonNull String getPackageName() {
return mPackageName;
}
+ /**
+ * @hide
+ */
+ @TestApi
public int getUid() {
return mUid;
}
+ /**
+ * @hide
+ */
+ @TestApi
public @NonNull String getPermGroupName() {
return mPermGroupName;
}
+ /**
+ * @hide
+ */
+ @TestApi
public long getLastAccess() {
return mLastAccess;
}
+ /**
+ * @hide
+ */
+ @TestApi
public boolean isActive() {
return mIsActive;
}
+ /**
+ * @hide
+ */
+ @TestApi
public boolean isPhoneCall() {
return mIsPhoneCall;
}
+ /**
+ * @hide
+ */
+ @TestApi
public @Nullable CharSequence getAttribution() {
return mAttribution;
}
@@ -80,6 +122,7 @@ public final class PermGroupUsage {
public String toString() {
return getClass().getSimpleName() + "@" + Integer.toHexString(System.identityHashCode(this))
+ " packageName: " + mPackageName + ", UID: " + mUid + ", permGroup: "
- + mPermGroupName + ", isActive: " + mIsActive + ", attribution: " + mAttribution;
+ + mPermGroupName + ", lastAccess: " + mLastAccess + ", isActive: " + mIsActive
+ + ", attribution: " + mAttribution;
}
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 177e422e7851..7669586cfc1f 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -26,6 +26,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityThread;
@@ -851,6 +852,7 @@ public final class PermissionManager {
*
* @hide
*/
+ @TestApi
@NonNull
@RequiresPermission(Manifest.permission.GET_APP_OPS_STATS)
public List<PermGroupUsage> getIndicatorAppOpUsageData() {
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 921911bbf479..2d6fa3c77966 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -71,13 +71,10 @@ public class PermissionUsageHelper {
private static final String PROPERTY_PERMISSIONS_HUB_2_ENABLED = "permissions_hub_2_enabled";
/** How long after an access to show it as "recent" */
- private static final String RECENT_ACCESS_TIME_MS = "recent_acccess_time_ms";
+ private static final String RECENT_ACCESS_TIME_MS = "recent_access_time_ms";
/** How long after an access to show it as "running" */
- private static final String RUNNING_ACCESS_TIME_MS = "running_acccess_time_ms";
-
- /** The name of the expected voice IME subtype */
- private static final String VOICE_IME_SUBTYPE = "voice";
+ private static final String RUNNING_ACCESS_TIME_MS = "running_access_time_ms";
private static final String SYSTEM_PKG = "android";
@@ -279,6 +276,10 @@ public class PermissionUsageHelper {
opEntry.getAttributedOpEntries().get(attributionTag);
long lastAccessTime = attrOpEntry.getLastAccessTime(opFlags);
+ if (attrOpEntry.isRunning()) {
+ lastAccessTime = now;
+ }
+
if (lastAccessTime < recentThreshold && !attrOpEntry.isRunning()) {
continue;
}
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 04a4ca47d305..13274c6f27ee 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -38,6 +38,8 @@ import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
+import com.android.internal.os.IResultReceiver;
+
/**
* An {@code AutofillService} is a service used to automatically fill the contents of the screen
* on behalf of a given user - for more information about autofill, read
@@ -575,6 +577,20 @@ public abstract class AutofillService extends Service {
*/
public static final String SERVICE_META_DATA = "android.autofill";
+ /**
+ * Name of the {@link IResultReceiver} extra used to return the primary result of a request.
+ *
+ * @hide
+ */
+ public static final String EXTRA_RESULT = "result";
+
+ /**
+ * Name of the {@link IResultReceiver} extra used to return the error reason of a request.
+ *
+ * @hide
+ */
+ public static final String EXTRA_ERROR = "error";
+
private final IAutoFillService mInterface = new IAutoFillService.Stub() {
@Override
public void onConnectedStateChanged(boolean connected) {
@@ -603,6 +619,14 @@ public abstract class AutofillService extends Service {
AutofillService::onSaveRequest,
AutofillService.this, request, new SaveCallback(callback)));
}
+
+ @Override
+ public void onSavedPasswordCountRequest(IResultReceiver receiver) {
+ mHandler.sendMessage(obtainMessage(
+ AutofillService::onSavedDatasetsInfoRequest,
+ AutofillService.this,
+ new SavedDatasetsInfoCallbackImpl(receiver, SavedDatasetsInfo.TYPE_PASSWORDS)));
+ }
};
private Handler mHandler;
@@ -673,6 +697,19 @@ public abstract class AutofillService extends Service {
@NonNull SaveCallback callback);
/**
+ * Called from system settings to display information about the datasets the user saved to this
+ * service.
+ *
+ * <p>There is no timeout for the request, but it's recommended to return the result within a
+ * few seconds, or the user may navigate away from the activity that would display the result.
+ *
+ * @param callback callback for responding to the request
+ */
+ public void onSavedDatasetsInfoRequest(@NonNull SavedDatasetsInfoCallback callback) {
+ callback.onError(SavedDatasetsInfoCallback.ERROR_UNSUPPORTED);
+ }
+
+ /**
* Called when the Android system disconnects from the service.
*
* <p> At this point this service may no longer be an active {@link AutofillService}.
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index 23a1a3fee47c..d88e0945bdca 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -31,4 +31,5 @@ oneway interface IAutoFillService {
void onConnectedStateChanged(boolean connected);
void onFillRequest(in FillRequest request, in IFillCallback callback);
void onSaveRequest(in SaveRequest request, in ISaveCallback callback);
+ void onSavedPasswordCountRequest(in IResultReceiver receiver);
}
diff --git a/core/java/android/service/autofill/SavedDatasetsInfo.java b/core/java/android/service/autofill/SavedDatasetsInfo.java
new file mode 100644
index 000000000000..6a4d2b834cef
--- /dev/null
+++ b/core/java/android/service/autofill/SavedDatasetsInfo.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+
+import com.android.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A result returned from
+ * {@link AutofillService#onSavedDatasetsInfoRequest(SavedDatasetsInfoCallback)}.
+ */
+@DataClass(
+ genToString = true,
+ genHiddenConstDefs = true,
+ genEqualsHashCode = true)
+public final class SavedDatasetsInfo {
+
+ /**
+ * Any other type of datasets.
+ */
+ public static final String TYPE_OTHER = "other";
+
+ /**
+ * Datasets such as login credentials.
+ */
+ public static final String TYPE_PASSWORDS = "passwords";
+
+ /**
+ * The type of the datasets that this info is about.
+ */
+ @NonNull
+ @Type
+ private final String mType;
+
+ /**
+ * The number of datasets of {@link #getType() this type} that the user has saved to the
+ * service.
+ */
+ @IntRange(from = 0)
+ private final int mCount;
+
+
+ // Code below generated by codegen v1.0.22.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/SavedDatasetsInfo.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /** @hide */
+ @StringDef(prefix = "TYPE_", value = {
+ TYPE_OTHER,
+ TYPE_PASSWORDS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface Type {}
+
+ /**
+ * Creates a new SavedDatasetsInfo.
+ *
+ * @param type
+ * The type of the datasets.
+ * @param count
+ * The number of datasets of this type that the user has saved to the service.
+ */
+ @DataClass.Generated.Member
+ public SavedDatasetsInfo(
+ @NonNull @Type String type,
+ @IntRange(from = 0) int count) {
+ this.mType = type;
+
+ if (!(java.util.Objects.equals(mType, TYPE_OTHER))
+ && !(java.util.Objects.equals(mType, TYPE_PASSWORDS))) {
+ throw new java.lang.IllegalArgumentException(
+ "type was " + mType + " but must be one of: "
+ + "TYPE_OTHER(" + TYPE_OTHER + "), "
+ + "TYPE_PASSWORDS(" + TYPE_PASSWORDS + ")");
+ }
+
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mType);
+ this.mCount = count;
+ com.android.internal.util.AnnotationValidations.validate(
+ IntRange.class, null, mCount,
+ "from", 0);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * The type of the datasets.
+ */
+ @DataClass.Generated.Member
+ public @NonNull @Type String getType() {
+ return mType;
+ }
+
+ /**
+ * The number of datasets of this type that the user has saved to the service.
+ */
+ @DataClass.Generated.Member
+ public @IntRange(from = 0) int getCount() {
+ return mCount;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "SavedDatasetsInfo { " +
+ "type = " + mType + ", " +
+ "count = " + mCount +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@android.annotation.Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(SavedDatasetsInfo other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ SavedDatasetsInfo that = (SavedDatasetsInfo) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && java.util.Objects.equals(mType, that.mType)
+ && mCount == that.mCount;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + java.util.Objects.hashCode(mType);
+ _hash = 31 * _hash + mCount;
+ return _hash;
+ }
+
+ @DataClass.Generated(
+ time = 1615325704446L,
+ codegenVersion = "1.0.22",
+ sourceFile = "frameworks/base/core/java/android/service/autofill/SavedDatasetsInfo.java",
+ inputSignatures = "public static final java.lang.String TYPE_OTHER\npublic static final java.lang.String TYPE_PASSWORDS\nprivate final @android.annotation.NonNull @android.service.autofill.SavedDatasetsInfo.Type java.lang.String mType\nprivate final @android.annotation.IntRange int mCount\nclass SavedDatasetsInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/service/autofill/SavedDatasetsInfoCallback.java b/core/java/android/service/autofill/SavedDatasetsInfoCallback.java
new file mode 100644
index 000000000000..a47105a23816
--- /dev/null
+++ b/core/java/android/service/autofill/SavedDatasetsInfoCallback.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Set;
+
+/**
+ * Handles the response to
+ * {@link AutofillService#onSavedDatasetsInfoRequest(SavedDatasetsInfoCallback)}.
+ * <p>
+ * Use {@link #onSuccess(Set)} to return the computed info about the datasets the user saved to this
+ * service. If there was an error querying the info, or if the service is unable to do so at this
+ * time (for example, if the user isn't logged in), call {@link #onError(int)}.
+ * <p>
+ * This callback can be used only once.
+ */
+public interface SavedDatasetsInfoCallback {
+
+ /** @hide */
+ @IntDef(prefix = {"ERROR_"}, value = {
+ ERROR_OTHER,
+ ERROR_UNSUPPORTED,
+ ERROR_NEEDS_USER_ACTION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Error {
+ }
+
+ /**
+ * The result could not be computed for any other reason.
+ */
+ int ERROR_OTHER = 0;
+ /**
+ * The service does not support this request.
+ */
+ int ERROR_UNSUPPORTED = 1;
+ /**
+ * The result cannot be computed until the user takes some action, such as setting up their
+ * account.
+ */
+ int ERROR_NEEDS_USER_ACTION = 2;
+
+ /**
+ * Successfully respond to the request with the info on each type of saved datasets.
+ */
+ void onSuccess(@NonNull Set<SavedDatasetsInfo> results);
+
+ /**
+ * Respond to the request with an error. System settings may display a suitable notice to the
+ * user.
+ */
+ void onError(@Error int error);
+}
diff --git a/core/java/android/service/autofill/SavedDatasetsInfoCallbackImpl.java b/core/java/android/service/autofill/SavedDatasetsInfoCallbackImpl.java
new file mode 100644
index 000000000000..b8a8cde12d3e
--- /dev/null
+++ b/core/java/android/service/autofill/SavedDatasetsInfoCallbackImpl.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import static android.service.autofill.AutofillService.EXTRA_ERROR;
+import static android.service.autofill.AutofillService.EXTRA_RESULT;
+
+import static com.android.internal.util.Preconditions.checkArgumentInRange;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.os.DeadObjectException;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.os.IResultReceiver;
+
+import java.util.Set;
+
+final class SavedDatasetsInfoCallbackImpl implements SavedDatasetsInfoCallback {
+ private static final String TAG = "AutofillService";
+
+ @NonNull
+ private final IResultReceiver mReceiver;
+ @NonNull
+ private final String mType;
+
+ /**
+ * Creates a {@link SavedDatasetsInfoCallback} that returns the {@link
+ * SavedDatasetsInfo#getCount() number} of saved datasets of {@code type} to the {@code
+ * receiver}.
+ */
+ SavedDatasetsInfoCallbackImpl(@NonNull IResultReceiver receiver, @NonNull String type) {
+ mReceiver = requireNonNull(receiver);
+ mType = requireNonNull(type);
+ }
+
+ @Override
+ public void onSuccess(@NonNull Set<SavedDatasetsInfo> results) {
+ requireNonNull(results);
+ if (results.isEmpty()) {
+ send(1, null);
+ return;
+ }
+ int count = -1;
+ for (SavedDatasetsInfo info : results) {
+ if (mType.equals(info.getType())) {
+ count = info.getCount();
+ }
+ }
+ if (count < 0) {
+ send(1, null);
+ return;
+ }
+ Bundle bundle = new Bundle(/* capacity= */ 1);
+ bundle.putInt(EXTRA_RESULT, count);
+ send(0, bundle);
+ }
+
+ @Override
+ public void onError(@Error int error) {
+ checkArgumentInRange(error, ERROR_OTHER, ERROR_NEEDS_USER_ACTION, "error");
+ Bundle bundle = new Bundle(/* capacity= */ 1);
+ bundle.putInt(EXTRA_ERROR, error);
+ send(1, bundle);
+ }
+
+ private void send(int resultCode, Bundle bundle) {
+ try {
+ mReceiver.send(resultCode, bundle);
+ } catch (DeadObjectException e) {
+ Log.w(TAG, "Failed to send onSavedPasswordCountRequest result: " + e);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index f1eef9fad8a1..82106b09ca5c 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1389,6 +1389,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
// If we are using BLAST, merge the transaction with the viewroot buffer transaction.
viewRoot.mergeWithNextTransaction(mRtTransaction, frameNumber);
return;
+ } else {
+ mRtTransaction.apply();
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index ec0a8d8ede9d..27e77bfe11dd 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16525,6 +16525,8 @@ public class BatteryStatsImpl extends BatteryStats {
// Pull the clock time. This may update the time and make a new history entry
// if we had originally pulled a time before the RTC was set.
getStartClockTime();
+
+ updateSystemServiceCallStats();
}
public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index 4f99c94e0dc5..f8ae0c1858f8 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -21,9 +21,7 @@ import android.hardware.SensorManager;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
-import android.os.Bundle;
import android.os.UidBatteryConsumer;
-import android.os.UserHandle;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -88,29 +86,31 @@ public class BatteryUsageStatsProvider {
}
/**
- * Returns snapshots of battery attribution data, one per supplied query.
+ * Returns true if the last update was too long ago for the tolerances specified
+ * by the supplied queries.
*/
- public List<BatteryUsageStats> getBatteryUsageStats(List<BatteryUsageStatsQuery> queries) {
-
- // TODO(b/174186345): instead of BatteryStatsHelper, use PowerCalculators directly.
- final BatteryStatsHelper batteryStatsHelper = new BatteryStatsHelper(mContext,
- false /* collectBatteryBroadcast */);
- batteryStatsHelper.create((Bundle) null);
- final List<UserHandle> users = new ArrayList<>();
- for (int i = 0; i < queries.size(); i++) {
+ public boolean shouldUpdateStats(List<BatteryUsageStatsQuery> queries,
+ long lastUpdateTimeStampMs) {
+ long allowableStatsAge = Long.MAX_VALUE;
+ for (int i = queries.size() - 1; i >= 0; i--) {
BatteryUsageStatsQuery query = queries.get(i);
- for (int userId : query.getUserIds()) {
- UserHandle userHandle = UserHandle.of(userId);
- if (!users.contains(userHandle)) {
- users.add(userHandle);
- }
- }
+ allowableStatsAge = Math.min(allowableStatsAge, query.getMaxStatsAge());
}
- batteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, users);
+ return mStats.mClocks.elapsedRealtime() - lastUpdateTimeStampMs > allowableStatsAge;
+ }
+
+ /**
+ * Returns snapshots of battery attribution data, one per supplied query.
+ */
+ public List<BatteryUsageStats> getBatteryUsageStats(List<BatteryUsageStatsQuery> queries) {
ArrayList<BatteryUsageStats> results = new ArrayList<>(queries.size());
- for (int i = 0; i < queries.size(); i++) {
- results.add(getBatteryUsageStats(queries.get(i)));
+ synchronized (mStats) {
+ mStats.prepareForDumpLocked();
+
+ for (int i = 0; i < queries.size(); i++) {
+ results.add(getBatteryUsageStats(queries.get(i)));
+ }
}
return results;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 38ef9d2ea525..1d462bc5dd48 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4440,6 +4440,13 @@
<permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to disable system sound effects when the user exits one of
+ the application's activities.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.DISABLE_SYSTEM_SOUND_EFFECTS"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an application to provide remote displays.
<p>Not for use by third-party applications.</p>
@hide -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 38e8f83ff767..dc4f52e980ce 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2862,6 +2862,13 @@
{@link android.content.Context#sendBroadcast(Intent, String)} being used.
Multiple tags can be specified separated by '|'. -->
<attr name="attributionTags"/>
+ <!-- Specifies whether a home sound effect should be played if the home app moves to
+ front after an activity with this flag set to <code>true</code>.
+ <p>The default value of this attribute is <code>true</code>.
+ <p>Also note that home sounds are only played if the device supports home sounds,
+ usually TVs.
+ <p>Requires permission {@code android.permission.DISABLE_SYSTEM_SOUND_EFFECTS}. -->
+ <attr name="playHomeTransitionSound" format="boolean"/>
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 3259cafb4f7e..16feb4fc7dac 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3093,6 +3093,8 @@
<public name="suppressesSpellChecker" />
<public name="usesPermissionFlags" />
<public name="requestOptimizedExternalStorageAccess" />
+ <!-- @hide @SystemApi -->
+ <public name="playHomeTransitionSound" />
</public-group>
<public-group type="drawable" first-id="0x010800b5">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e2974bce694c..c63a02b55081 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5664,6 +5664,15 @@
<!-- Error message. This text lets the user know that their current personal apps can't open this specific content. [CHAR LIMIT=NONE] -->
<string name="resolver_no_personal_apps_available_resolve">No personal apps can open this content</string>
+ <!-- Dialog title. User must choose between opening content in a cross-profile app or same-profile browser. [CHAR LIMIT=NONE] -->
+ <string name="miniresolver_open_in_personal">Open in <xliff:g id="app" example="YouTube">%s</xliff:g> in personal profile?</string>
+ <!-- Dialog title. User must choose between opening content in a cross-profile app or same-profile browser. [CHAR LIMIT=NONE] -->
+ <string name="miniresolver_open_in_work">Open in <xliff:g id="app" example="YouTube">%s</xliff:g> in work profile?</string>
+ <!-- Button option. Open the link in the personal browser. [CHAR LIMIT=NONE] -->
+ <string name="miniresolver_use_personal_browser">Use personal browser</string>
+ <!-- Button option. Open the link in the work browser. [CHAR LIMIT=NONE] -->
+ <string name="miniresolver_use_work_browser">Use work browser</string>
+
<!-- Icc depersonalization related strings -->
<!-- Label text for PIN entry widget on SIM Network Depersonalization panel [CHAR LIMIT=none] -->
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY">SIM network unlock PIN</string>
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
index 7ef1d5e426cc..6d9e2ea5acab 100644
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
@@ -51,7 +51,7 @@ public class AppSearchSessionUnitTest {
CompletableFuture<AppSearchResult<SetSchemaResponse>> schemaFuture =
new CompletableFuture<>();
mSearchSession.setSchema(
- new SetSchemaRequest.Builder().setForceOverride(true).build(), mExecutor,
+ new SetSchemaRequest.Builder().setForceOverride(true).build(), mExecutor, mExecutor,
schemaFuture::complete);
schemaFuture.get().getResultValue();
diff --git a/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java b/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
index 41cd4c562bd8..2833ea3f9ac0 100644
--- a/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
@@ -49,7 +49,6 @@ import java.util.function.Consumer;
*/
@Presubmit
@SmallTest
-@FlakyTest(detail = "promote once confirmed flake-free")
@RunWith(MockitoJUnitRunner.class)
public class ViewGroupScrollCaptureTest {
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
index 0f591433a84e..d36f06ab683a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
@@ -158,4 +158,22 @@ public class BatteryUsageStatsProviderTest {
assertThat(item.time).isEqualTo(elapsedTimeMs);
}
+
+ @Test
+ public void shouldUpdateStats() {
+ Context context = InstrumentationRegistry.getContext();
+ BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context,
+ mStatsRule.getBatteryStats());
+
+ final List<BatteryUsageStatsQuery> queries = List.of(
+ new BatteryUsageStatsQuery.Builder().setMaxStatsAgeMs(1000).build(),
+ new BatteryUsageStatsQuery.Builder().setMaxStatsAgeMs(2000).build()
+ );
+
+ mStatsRule.setTime(10500, 0);
+ assertThat(provider.shouldUpdateStats(queries, 10000)).isFalse();
+
+ mStatsRule.setTime(11500, 0);
+ assertThat(provider.shouldUpdateStats(queries, 10000)).isTrue();
+ }
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index cafda0966fc4..c48fd8b8b6ae 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -34,9 +34,11 @@ import android.graphics.fonts.FontFamily;
import android.graphics.fonts.FontStyle;
import android.graphics.fonts.FontVariationAxis;
import android.graphics.fonts.SystemFonts;
+import android.icu.util.ULocale;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.SharedMemory;
+import android.os.SystemProperties;
import android.os.Trace;
import android.provider.FontRequest;
import android.provider.FontsContract;
@@ -45,6 +47,7 @@ import android.system.OsConstants;
import android.text.FontConfig;
import android.util.ArrayMap;
import android.util.Base64;
+import android.util.Log;
import android.util.LongSparseArray;
import android.util.LruCache;
import android.util.SparseArray;
@@ -1375,13 +1378,35 @@ public class Typeface {
static {
// Preload Roboto-Regular.ttf in Zygote for improving app launch performance.
- // TODO: add new attribute to fonts.xml to preload fonts in Zygote.
preloadFontFile("/system/fonts/Roboto-Regular.ttf");
+
+ String locale = SystemProperties.get("persist.sys.locale", "en-US");
+ String script = ULocale.addLikelySubtags(ULocale.forLanguageTag(locale)).getScript();
+
+ FontConfig config = SystemFonts.getSystemPreinstalledFontConfig();
+ for (int i = 0; i < config.getFontFamilies().size(); ++i) {
+ FontConfig.FontFamily family = config.getFontFamilies().get(i);
+ boolean loadFamily = false;
+ for (int j = 0; j < family.getLocaleList().size(); ++j) {
+ String fontScript = ULocale.addLikelySubtags(
+ ULocale.forLocale(family.getLocaleList().get(j))).getScript();
+ loadFamily = fontScript.equals(script);
+ if (loadFamily) {
+ break;
+ }
+ }
+ if (loadFamily) {
+ for (int j = 0; j < family.getFontList().size(); ++j) {
+ preloadFontFile(family.getFontList().get(j).getFile().getAbsolutePath());
+ }
+ }
+ }
}
private static void preloadFontFile(String filePath) {
File file = new File(filePath);
if (file.exists()) {
+ Log.i(TAG, "Preloading " + file.getAbsolutePath());
nativeWarmUpCache(filePath);
}
}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 24d73efebe54..3616a4d66399 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -276,7 +276,11 @@ public class GradientDrawable extends Drawable {
*/
@Nullable
public float[] getCornerRadii() {
- return mGradientState.mRadiusArray.clone();
+ float[] radii = mGradientState.mRadiusArray;
+ if (radii == null) {
+ return null;
+ }
+ return radii.clone();
}
/**
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index 5dd250c8239e..98b9584f7b4a 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -60,17 +60,13 @@ final class RippleShader extends RuntimeShader {
+ " float d = distance(uv, xy);\n"
+ " return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius);\n"
+ "}\n"
- + "\n"
- + "float getRingMask(vec2 frag, vec2 center, float r, float progress) {\n"
- + " float dist = distance(frag, center);\n"
- + " float expansion = r * .6;\n"
- + " r = r * min(1.,progress);\n"
- + " float minD = max(r - expansion, 0.);\n"
- + " float maxD = r + expansion;\n"
- + " if (dist > maxD || dist < minD) return .0;\n"
- + " return min(maxD - dist, dist - minD) / expansion; \n"
+ + "float softRing(vec2 uv, vec2 xy, float radius, float progress, float blur) {\n"
+ + " float thickness = 0.2 * radius;\n"
+ + " float currentRadius = radius * progress;\n"
+ + " float circle_outer = softCircle(uv, xy, currentRadius + thickness, blur);\n"
+ + " float circle_inner = softCircle(uv, xy, currentRadius - thickness, blur);\n"
+ + " return clamp(circle_outer - circle_inner, 0., 1.);\n"
+ "}\n"
- + "\n"
+ "float subProgress(float start, float end, float progress) {\n"
+ " float sub = clamp(progress, start, end);\n"
+ " return (sub - start) / (end - start); \n"
@@ -80,8 +76,8 @@ final class RippleShader extends RuntimeShader {
+ " float fadeOutNoise = subProgress(0.375, 1., in_progress);\n"
+ " float fadeOutRipple = subProgress(0.375, 0.75, in_progress);\n"
+ " vec2 center = mix(in_touch, in_origin, fadeIn);\n"
- + " float ring = getRingMask(p, center, in_maxRadius, fadeIn);\n"
- + " float alpha = min(fadeIn, 1. - fadeOutNoise);\n"
+ + " float ring = softRing(p, center, in_maxRadius, fadeIn, 0.45);\n"
+ + " float alpha = 1. - fadeOutNoise;\n"
+ " vec2 uv = p * in_resolutionScale;\n"
+ " vec2 densityUv = uv - mod(uv, in_noiseScale);\n"
+ " float sparkle = sparkles(densityUv, in_noisePhase) * ring * alpha;\n"
@@ -137,8 +133,7 @@ final class RippleShader extends RuntimeShader {
}
public void setResolution(float w, float h, int density) {
- float noiseScale = 0.8f;
- float densityScale = density * DisplayMetrics.DENSITY_DEFAULT_SCALE * 0.5f * noiseScale;
+ float densityScale = density * DisplayMetrics.DENSITY_DEFAULT_SCALE * 0.5f;
setUniform("in_resolutionScale", new float[] {1f / w, 1f / h});
setUniform("in_noiseScale", new float[] {densityScale / w, densityScale / h});
}
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 35b1c169f283..72cea0cacd12 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -139,4 +139,18 @@ public class AndroidKeyStoreMaintenance {
return SYSTEM_ERROR;
}
}
+
+ /**
+ * Informs Keystore 2.0 that an off body event was detected.
+ */
+ public static void onDeviceOffBody() {
+ if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return;
+ try {
+ getService().onDeviceOffBody();
+ } catch (Exception e) {
+ // TODO This fails open. This is not a regression with respect to keystore1 but it
+ // should get fixed.
+ Log.e(TAG, "Error while reporting device off body event.", e);
+ }
+ }
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index a08f390c9fd3..b05149ef75bc 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -1204,6 +1204,7 @@ public class KeyStore {
* Notify keystore that the device went off-body.
*/
public void onDeviceOffBody() {
+ AndroidKeyStoreMaintenance.onDeviceOffBody();
try {
mBinder.onDeviceOffBody();
} catch (RemoteException e) {
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 6ac3821d0f9c..75e248e06b2b 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -18,8 +18,7 @@ package android.security;
import android.annotation.NonNull;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
-import android.os.Build;
+import android.compat.annotation.Disabled;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
@@ -86,7 +85,7 @@ public class KeyStore2 {
* successfully conclude an operation.
*/
@ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ @Disabled // See b/180133780
static final long KEYSTORE_OPERATION_CREATION_MAY_FAIL = 169897160L;
// Never use mBinder directly, use KeyStore2.getService() instead or better yet
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index ade63e5b832c..5d9fad5b676e 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -45,7 +45,8 @@ sk_sp<SkColorSpace> ImageDecoder::getDefaultColorSpace() const {
return SkColorSpace::MakeSRGB();
}
-ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker)
+ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker,
+ SkCodec::ZeroInitialized zeroInit)
: mCodec(std::move(codec))
, mPeeker(std::move(peeker))
, mDecodeSize(mCodec->codec()->dimensions())
@@ -57,6 +58,7 @@ ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChu
mTargetSize = swapWidthHeight() ? SkISize { mDecodeSize.height(), mDecodeSize.width() }
: mDecodeSize;
this->rewind();
+ mOptions.fZeroInitialized = zeroInit;
}
ImageDecoder::~ImageDecoder() = default;
@@ -446,10 +448,17 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
ALOGE("Failed to invert matrix!");
}
}
+
+ // Even if the client did not provide zero initialized memory, the
+ // memory we decode into is.
+ mOptions.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
}
auto result = mCodec->getAndroidPixels(decodeInfo, decodePixels, decodeRowBytes, &mOptions);
+ // The next call to decode() may not provide zero initialized memory.
+ mOptions.fZeroInitialized = SkCodec::kNo_ZeroInitialized;
+
if (scale || handleOrigin || mCropRect) {
SkBitmap scaledBm;
if (!scaledBm.installPixels(outputInfo, pixels, rowBytes)) {
diff --git a/libs/hwui/hwui/ImageDecoder.h b/libs/hwui/hwui/ImageDecoder.h
index cbfffd5e9291..cef2233fc371 100644
--- a/libs/hwui/hwui/ImageDecoder.h
+++ b/libs/hwui/hwui/ImageDecoder.h
@@ -34,8 +34,8 @@ public:
std::unique_ptr<SkAndroidCodec> mCodec;
sk_sp<SkPngChunkReader> mPeeker;
- ImageDecoder(std::unique_ptr<SkAndroidCodec> codec,
- sk_sp<SkPngChunkReader> peeker = nullptr);
+ ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker = nullptr,
+ SkCodec::ZeroInitialized zeroInit = SkCodec::kNo_ZeroInitialized);
~ImageDecoder();
SkISize getSampledDimensions(int sampleSize) const;
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index ad7741b61e9f..f7b8c014be6e 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -141,7 +141,8 @@ static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream,
}
const bool isNinePatch = peeker->mPatch != nullptr;
- ImageDecoder* decoder = new ImageDecoder(std::move(androidCodec), std::move(peeker));
+ ImageDecoder* decoder = new ImageDecoder(std::move(androidCodec), std::move(peeker),
+ SkCodec::kYes_ZeroInitialized);
return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID,
reinterpret_cast<jlong>(decoder), decoder->width(), decoder->height(),
animated, isNinePatch);
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 9dcc391bd31b..f3f55333d207 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -232,8 +232,8 @@ package android.net {
method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
method public final void sendQosCallbackError(int, int);
- method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
- method public final void sendQosSessionLost(int, int);
+ method public final void sendQosSessionAvailable(int, int, @NonNull android.net.QosSessionAttributes);
+ method public final void sendQosSessionLost(int, int, int);
method public final void sendSocketKeepaliveEvent(int, int);
method @Deprecated public void setLegacySubtype(int, @NonNull String);
method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
@@ -385,6 +385,7 @@ package android.net {
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
field public static final int TYPE_EPS_BEARER = 1; // 0x1
+ field public static final int TYPE_NR_BEARER = 2; // 0x2
}
public interface QosSessionAttributes {
diff --git a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
index c5464d32412b..cbd6193744b9 100644
--- a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -22,6 +22,7 @@ import android.net.NetworkInfo;
import android.net.NetworkScore;
import android.net.QosSession;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
/**
* Interface for NetworkAgents to send network properties.
@@ -37,6 +38,7 @@ oneway interface INetworkAgentRegistry {
void sendSocketKeepaliveEvent(int slot, int reason);
void sendUnderlyingNetworks(in @nullable List<Network> networks);
void sendEpsQosSessionAvailable(int callbackId, in QosSession session, in EpsBearerQosSessionAttributes attributes);
+ void sendNrQosSessionAvailable(int callbackId, in QosSession session, in NrQosSessionAttributes attributes);
void sendQosSessionLost(int qosCallbackId, in QosSession session);
void sendQosCallbackError(int qosCallbackId, int exceptionType);
}
diff --git a/packages/Connectivity/framework/src/android/net/IQosCallback.aidl b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
index 91c75759f85c..c9735419f7dd 100644
--- a/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
+++ b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
@@ -19,6 +19,7 @@ package android.net;
import android.os.Bundle;
import android.net.QosSession;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
/**
* AIDL interface for QosCallback
@@ -29,6 +30,8 @@ oneway interface IQosCallback
{
void onQosEpsBearerSessionAvailable(in QosSession session,
in EpsBearerQosSessionAttributes attributes);
+ void onNrQosSessionAvailable(in QosSession session,
+ in NrQosSessionAttributes attributes);
void onQosSessionLost(in QosSession session);
void onError(in int type);
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
index b3d9616cead7..f7cd4f6954bc 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
@@ -32,6 +32,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -1160,29 +1161,37 @@ public abstract class NetworkAgent {
/**
- * Sends the attributes of Eps Bearer Qos Session back to the Application
+ * Sends the attributes of Qos Session back to the Application
*
* @param qosCallbackId the callback id that the session belongs to
- * @param sessionId the unique session id across all Eps Bearer Qos Sessions
- * @param attributes the attributes of the Eps Qos Session
+ * @param sessionId the unique session id across all Qos Sessions
+ * @param attributes the attributes of the Qos Session
*/
public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId,
- @NonNull final EpsBearerQosSessionAttributes attributes) {
+ @NonNull final QosSessionAttributes attributes) {
Objects.requireNonNull(attributes, "The attributes must be non-null");
- queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
- new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
- attributes));
+ if (attributes instanceof EpsBearerQosSessionAttributes) {
+ queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
+ (EpsBearerQosSessionAttributes)attributes));
+ } else if (attributes instanceof NrQosSessionAttributes) {
+ queueOrSendMessage(ra -> ra.sendNrQosSessionAvailable(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_NR_BEARER),
+ (NrQosSessionAttributes)attributes));
+ }
}
/**
- * Sends event that the Eps Qos Session was lost.
+ * Sends event that the Qos Session was lost.
*
* @param qosCallbackId the callback id that the session belongs to
- * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+ * @param sessionId the unique session id across all Qos Sessions
+ * @param qosSessionType the session type {@code QosSesson#QosSessionType}
*/
- public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) {
+ public final void sendQosSessionLost(final int qosCallbackId,
+ final int sessionId, final int qosSessionType) {
queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId,
- new QosSession(sessionId, QosSession.TYPE_EPS_BEARER)));
+ new QosSession(sessionId, qosSessionType)));
}
/**
diff --git a/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
index bdb4ad68cd7b..de0fc243b43b 100644
--- a/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
+++ b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
@@ -19,6 +19,7 @@ package android.net;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import com.android.internal.annotations.VisibleForTesting;
@@ -84,6 +85,25 @@ class QosCallbackConnection extends android.net.IQosCallback.Stub {
}
/**
+ * Called when either the {@link NrQosSessionAttributes} has changed or on the first time
+ * the attributes have become available.
+ *
+ * @param session the session that is now available
+ * @param attributes the corresponding attributes of session
+ */
+ @Override
+ public void onNrQosSessionAvailable(@NonNull final QosSession session,
+ @NonNull final NrQosSessionAttributes attributes) {
+
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ callback.onQosSessionAvailable(session, attributes);
+ }
+ });
+ }
+
+ /**
* Called when the session is lost.
*
* @param session the session that was lost
diff --git a/packages/Connectivity/framework/src/android/net/QosSession.java b/packages/Connectivity/framework/src/android/net/QosSession.java
index 4f3bb77c5877..93f2ff2bf724 100644
--- a/packages/Connectivity/framework/src/android/net/QosSession.java
+++ b/packages/Connectivity/framework/src/android/net/QosSession.java
@@ -36,6 +36,11 @@ public final class QosSession implements Parcelable {
*/
public static final int TYPE_EPS_BEARER = 1;
+ /**
+ * The {@link QosSession} is a NR Session.
+ */
+ public static final int TYPE_NR_BEARER = 2;
+
private final int mSessionId;
private final int mSessionType;
@@ -100,6 +105,7 @@ public final class QosSession implements Parcelable {
*/
@IntDef(value = {
TYPE_EPS_BEARER,
+ TYPE_NR_BEARER,
})
@interface QosSessionType {}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index 231babea97c2..dd9fc2c7c142 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -23,5 +23,6 @@ android_library {
apex_available: [
"//apex_available:platform",
"com.android.cellbroadcast",
+ "com.android.permission",
],
}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
new file mode 100644
index 000000000000..24d53ab84653
--- /dev/null
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<androidx.coordinatorlayout.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/content_parent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:transitionGroup="true">
+
+ <com.google.android.material.appbar.AppBarLayout
+ android:id="@+id/app_bar"
+ android:layout_width="match_parent"
+ android:layout_height="180dp"
+ android:theme="@style/Theme.CollapsingToolbar.Settings">
+
+ <com.android.settingslib.collapsingtoolbar.AdjustableToolbarLayout
+ android:id="@+id/collapsing_toolbar"
+ android:background="?android:attr/colorPrimary"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:maxLines="3"
+ app:contentScrim="?android:attr/colorPrimary"
+ app:collapsedTitleTextAppearance="@style/CollapsingToolbarTitle.Collapsed"
+ app:statusBarScrim="?android:attr/colorPrimary"
+ app:layout_scrollFlags="scroll|exitUntilCollapsed"
+ app:expandedTitleMarginStart="18dp"
+ app:expandedTitleMarginEnd="18dp"
+ app:toolbarId="@id/action_bar">
+
+ <Toolbar
+ android:id="@+id/action_bar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:theme="?android:attr/actionBarTheme"
+ app:layout_collapseMode="pin"/>
+
+ </com.android.settingslib.collapsingtoolbar.AdjustableToolbarLayout>
+ </com.google.android.material.appbar.AppBarLayout>
+
+ <FrameLayout
+ android:id="@+id/content_frame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
+</androidx.coordinatorlayout.widget.CoordinatorLayout> \ No newline at end of file
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/collapsing_toolbar_base_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/collapsing_toolbar_base_layout.xml
index e376930645ce..c799b9962828 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/collapsing_toolbar_base_layout.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/collapsing_toolbar_base_layout.xml
@@ -14,47 +14,23 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<androidx.coordinatorlayout.widget.CoordinatorLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
+<!-- The main content view -->
+<LinearLayout
android:id="@+id/content_parent"
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:transitionGroup="true">
-
- <com.google.android.material.appbar.AppBarLayout
- android:id="@+id/app_bar"
+ android:fitsSystemWindows="true"
+ android:transitionGroup="true"
+ android:orientation="vertical">
+ <Toolbar
+ android:id="@+id/action_bar"
+ style="?android:attr/actionBarStyle"
android:layout_width="match_parent"
- android:layout_height="180dp"
- android:theme="@style/Theme.CollapsingToolbar.Settings">
-
- <com.android.settingslib.collapsingtoolbar.AdjustableToolbarLayout
- android:id="@+id/collapsing_toolbar"
- android:background="?android:attr/colorPrimary"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:maxLines="3"
- app:contentScrim="?android:attr/colorPrimary"
- app:collapsedTitleTextAppearance="@style/CollapsingToolbarTitle.Collapsed"
- app:statusBarScrim="?android:attr/colorPrimary"
- app:layout_scrollFlags="scroll|exitUntilCollapsed"
- app:expandedTitleMarginStart="18dp"
- app:expandedTitleMarginEnd="18dp"
- app:toolbarId="@id/action_bar">
-
- <Toolbar
- android:id="@+id/action_bar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:theme="?android:attr/actionBarTheme"
- app:layout_collapseMode="pin"/>
-
- </com.android.settingslib.collapsingtoolbar.AdjustableToolbarLayout>
- </com.google.android.material.appbar.AppBarLayout>
-
+ android:layout_height="wrap_content"
+ android:theme="?android:attr/actionBarTheme" />
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
-</androidx.coordinatorlayout.widget.CoordinatorLayout> \ No newline at end of file
+ android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/toolbar_base_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/toolbar_base_layout.xml
deleted file mode 100644
index c799b9962828..000000000000
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/toolbar_base_layout.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!-- The main content view -->
-<LinearLayout
- android:id="@+id/content_parent"
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fitsSystemWindows="true"
- android:transitionGroup="true"
- android:orientation="vertical">
- <Toolbar
- android:id="@+id/action_bar"
- style="?android:attr/actionBarStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:theme="?android:attr/actionBarTheme" />
- <FrameLayout
- android:id="@+id/content_frame"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
-</LinearLayout>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index ad94cd0318a7..957bac742703 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -24,7 +24,6 @@ import android.view.ViewGroup;
import android.widget.Toolbar;
import androidx.annotation.Nullable;
-import androidx.core.os.BuildCompat;
import androidx.fragment.app.FragmentActivity;
import com.google.android.material.appbar.CollapsingToolbarLayout;
@@ -41,15 +40,8 @@ public class CollapsingToolbarBaseActivity extends FragmentActivity {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- // TODO(b/181723278): Update the version check after SDK for S is finalized
- // The collapsing toolbar is only supported if the android platform version is S or higher.
- // Otherwise the regular action bar will be shown.
- if (BuildCompat.isAtLeastS()) {
- super.setContentView(R.layout.collapsing_toolbar_base_layout);
- mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
- } else {
- super.setContentView(R.layout.toolbar_base_layout);
- }
+ super.setContentView(R.layout.collapsing_toolbar_base_layout);
+ mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
final Toolbar toolbar = findViewById(R.id.action_bar);
setActionBar(toolbar);
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
new file mode 100644
index 000000000000..c4c74ffc719b
--- /dev/null
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.collapsingtoolbar;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.Toolbar;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.material.appbar.CollapsingToolbarLayout;
+
+/**
+ * A base fragment that has a collapsing toolbar layout for enabling the collapsing toolbar design.
+ */
+public abstract class CollapsingToolbarBaseFragment extends Fragment {
+
+ @Nullable
+ private CollapsingToolbarLayout mCollapsingToolbarLayout;
+ @NonNull
+ private Toolbar mToolbar;
+ @NonNull
+ private FrameLayout mContentFrameLayout;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.collapsing_toolbar_base_layout, container,
+ false);
+ mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
+ mToolbar = view.findViewById(R.id.action_bar);
+ mContentFrameLayout = view.findViewById(R.id.content_frame);
+ return view;
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ requireActivity().setActionBar(mToolbar);
+ }
+
+ /**
+ * Return the collapsing toolbar layout.
+ */
+ @Nullable
+ public CollapsingToolbarLayout getCollapsingToolbarLayout() {
+ return mCollapsingToolbarLayout;
+ }
+
+ /**
+ * Return the content frame layout.
+ */
+ @NonNull
+ public FrameLayout getContentFrameLayout() {
+ return mContentFrameLayout;
+ }
+}
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index be49e1f8c71e..886f98e55d67 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -124,6 +124,7 @@
<attr name="darkIconTheme" format="reference" />
<attr name="wallpaperTextColor" format="reference|color" />
<attr name="wallpaperTextColorSecondary" format="reference|color" />
+ <attr name="wallpaperTextColorAccent" format="reference|color" />
<attr name="backgroundProtectedStyle" format="reference" />
<declare-styleable name="SmartReplyView">
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index af6df32a02b0..fbe7175b757f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -591,4 +591,12 @@
<!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
<bool name="allow_force_nav_bar_handle_opaque">true</bool>
+
+ <!-- Whether a transition of ACTIVITY_TYPE_DREAM to the home app should play a home sound
+ effect -->
+ <bool name="config_playHomeSoundAfterDream">false</bool>
+
+ <!-- Whether a transition of ACTIVITY_TYPE_ASSISTANT to the home app should play a home sound
+ effect -->
+ <bool name="config_playHomeSoundAfterAssistant">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 935f0259fe86..5e70f189da83 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -239,10 +239,8 @@
<string name="screenshot_edit_label">Edit</string>
<!-- Content description indicating that tapping the element will allow editing the screenshot [CHAR LIMIT=NONE] -->
<string name="screenshot_edit_description">Edit screenshot</string>
- <!-- Label for UI element which allows scrolling and extending the screenshot to be taller [CHAR LIMIT=30] -->
- <string name="screenshot_scroll_label">Scroll</string>
- <!-- Content description UI element which allows scrolling and extending the screenshot to be taller [CHAR LIMIT=NONE] -->
- <string name="screenshot_scroll_description">Scroll screenshot</string>
+ <!-- Label for UI element which allows the user to capture additional off-screen content in a screenshot. [CHAR LIMIT=30] -->
+ <string name="screenshot_scroll_label">Capture more</string>
<!-- Content description indicating that tapping a button will dismiss the screenshots UI [CHAR LIMIT=NONE] -->
<string name="screenshot_dismiss_description">Dismiss screenshot</string>
<!-- Content description indicating that the view is a preview of the screenshot that was just taken [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4a661dcecce8..ecc1a5c831b8 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -321,6 +321,7 @@
<item name="darkIconTheme">@style/DualToneDarkTheme</item>
<item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
<item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_dark</item>
+ <item name="wallpaperTextColorAccent">@*android:color/system_accent1_100</item>
<item name="android:colorError">@*android:color/error_color_material_dark</item>
<item name="android:colorControlHighlight">@*android:color/primary_text_material_dark</item>
<item name="*android:lockPatternStyle">@style/LockPatternStyle</item>
@@ -337,6 +338,7 @@
<style name="Theme.SystemUI.Light">
<item name="wallpaperTextColor">@*android:color/primary_text_material_light</item>
<item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item>
+ <item name="wallpaperTextColorAccent">@*android:color/system_accent2_600</item>
<item name="android:colorError">@*android:color/error_color_material_light</item>
<item name="android:colorControlHighlight">#40000000</item>
<item name="shadowRadius">0</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index 3f0e3eb84424..ab219f36bab3 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -131,7 +131,7 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie
private void initColors() {
mLockScreenColor = Utils.getColorAttrDefaultColor(getContext(),
- com.android.systemui.R.attr.wallpaperTextColor);
+ com.android.systemui.R.attr.wallpaperTextColorAccent);
mView.setColors(mDozingColor, mLockScreenColor);
mView.animateDoze(mIsDozing, false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index 378907c400d7..e2748437c0c6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -62,7 +62,8 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
mBgProtection = findViewById(R.id.udfps_keyguard_fp_bg);
- mWallpaperTexColor = Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor);
+ mWallpaperTexColor = Utils.getColorAttrDefaultColor(mContext,
+ R.attr.wallpaperTextColorAccent);
mTextColorPrimary = Utils.getColorAttrDefaultColor(mContext,
android.R.attr.textColorPrimary);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java b/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java
index dd3d02a86672..31e49390b9b8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java
@@ -16,38 +16,64 @@
package com.android.systemui.media.systemsounds;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.media.AudioManager;
+import android.util.Slog;
+import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import javax.inject.Inject;
/**
- * If a sound effect is defined for {@link android.media.AudioManager#FX_HOME}, a sound is played
- * when the home task moves to front and the last task that moved to front was not the home task.
+ * If a sound effect is defined for {@link android.media.AudioManager#FX_HOME}, a
+ * {@link TaskStackChangeListener} is registered to play a home sound effect when conditions
+ * documented at {@link #handleTaskStackChanged} apply.
*/
@SysUISingleton
public class HomeSoundEffectController extends SystemUI {
+ private static final String TAG = "HomeSoundEffectController";
private final AudioManager mAudioManager;
private final TaskStackChangeListeners mTaskStackChangeListeners;
+ private final ActivityManagerWrapper mActivityManagerWrapper;
+ private final PackageManager mPm;
+ private final boolean mPlayHomeSoundAfterAssistant;
+ private final boolean mPlayHomeSoundAfterDream;
// Initialize true because home sound should not be played when the system boots.
private boolean mIsLastTaskHome = true;
+ // mLastHomePackageName could go out of sync in rare circumstances if launcher changes,
+ // but it's cheaper than the alternative and potential impact is low
+ private String mLastHomePackageName;
+ private @WindowConfiguration.ActivityType int mLastActivityType;
+ private boolean mLastActivityHasNoHomeSound = false;
+ private int mLastTaskId;
@Inject
public HomeSoundEffectController(
Context context,
AudioManager audioManager,
- TaskStackChangeListeners taskStackChangeListeners) {
+ TaskStackChangeListeners taskStackChangeListeners,
+ ActivityManagerWrapper activityManagerWrapper,
+ PackageManager packageManager) {
super(context);
mAudioManager = audioManager;
mTaskStackChangeListeners = taskStackChangeListeners;
+ mActivityManagerWrapper = activityManagerWrapper;
+ mPm = packageManager;
+ mPlayHomeSoundAfterAssistant = context.getResources().getBoolean(
+ R.bool.config_playHomeSoundAfterAssistant);
+ mPlayHomeSoundAfterDream = context.getResources().getBoolean(
+ R.bool.config_playHomeSoundAfterDream);
}
@Override
@@ -56,27 +82,94 @@ public class HomeSoundEffectController extends SystemUI {
mTaskStackChangeListeners.registerTaskStackListener(
new TaskStackChangeListener() {
@Override
- public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
- handleHomeTaskMovedToFront(taskInfo);
+ public void onTaskStackChanged() {
+ ActivityManager.RunningTaskInfo currentTask =
+ mActivityManagerWrapper.getRunningTask();
+ if (currentTask == null || currentTask.topActivityInfo == null) {
+ return;
+ }
+ handleTaskStackChanged(currentTask);
}
});
}
}
- private boolean isHomeTask(ActivityManager.RunningTaskInfo taskInfo) {
- return taskInfo.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_HOME;
+ private boolean hasFlagNoSound(ActivityInfo activityInfo) {
+ if ((activityInfo.privateFlags & ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND) == 0) {
+ // Only allow flag if app has permission
+ if (mPm.checkPermission(Manifest.permission.DISABLE_SYSTEM_SOUND_EFFECTS,
+ activityInfo.packageName) == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ } else {
+ Slog.w(TAG,
+ "Activity has flag playHomeTransition set to false but doesn't hold "
+ + "required permission "
+ + Manifest.permission.DISABLE_SYSTEM_SOUND_EFFECTS);
+ return false;
+ }
+ }
+ return false;
}
/**
- * To enable a home sound, check if the home app moves to front.
+ * The home sound is played if all of the following conditions are met:
+ * <ul>
+ * <li>The last task which moved to front was not home. This avoids playing the sound
+ * e.g. after FallbackHome transitions to home, another activity of the home app like a
+ * notification panel moved to front, or in case the home app crashed.</li>
+ * <li>The current activity which moved to front is home</li>
+ * <li>The topActivity of the last task has {@link android.R.attr#playHomeTransitionSound} set
+ * to <code>true</code>.</li>
+ * <li>The topActivity of the last task is not of type
+ * {@link WindowConfiguration#ACTIVITY_TYPE_ASSISTANT} if config_playHomeSoundAfterAssistant is
+ * set to <code>false</code> (default).</li>
+ * <li>The topActivity of the last task is not of type
+ * {@link WindowConfiguration#ACTIVITY_TYPE_DREAM} if config_playHomeSoundAfterDream is
+ * set to <code>false</code> (default).</li>
+ * </ul>
*/
- private void handleHomeTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
- boolean isCurrentTaskHome = isHomeTask(taskInfo);
- // If the last task is home we don't want to play the home sound. This avoids playing
- // the home sound after FallbackHome transitions to Home
- if (!mIsLastTaskHome && isCurrentTaskHome) {
+ private boolean shouldPlayHomeSoundForCurrentTransition(
+ ActivityManager.RunningTaskInfo currentTask) {
+ boolean isHomeActivity =
+ currentTask.topActivityType == WindowConfiguration.ACTIVITY_TYPE_HOME;
+ if (currentTask.taskId == mLastTaskId) {
+ return false;
+ }
+ if (mIsLastTaskHome || !isHomeActivity) {
+ return false;
+ }
+ if (mLastActivityHasNoHomeSound) {
+ return false;
+ }
+ if (mLastActivityType == WindowConfiguration.ACTIVITY_TYPE_ASSISTANT
+ && !mPlayHomeSoundAfterAssistant) {
+ return false;
+ }
+ if (mLastActivityType == WindowConfiguration.ACTIVITY_TYPE_DREAM
+ && !mPlayHomeSoundAfterDream) {
+ return false;
+ }
+ return true;
+ }
+
+ private void updateLastTaskInfo(ActivityManager.RunningTaskInfo currentTask) {
+ mLastTaskId = currentTask.taskId;
+ mLastActivityType = currentTask.topActivityType;
+ mLastActivityHasNoHomeSound = hasFlagNoSound(currentTask.topActivityInfo);
+ boolean isHomeActivity =
+ currentTask.topActivityType == WindowConfiguration.ACTIVITY_TYPE_HOME;
+ boolean isHomePackage = currentTask.topActivityInfo.packageName.equals(
+ mLastHomePackageName);
+ mIsLastTaskHome = isHomeActivity || isHomePackage;
+ if (isHomeActivity && !isHomePackage) {
+ mLastHomePackageName = currentTask.topActivityInfo.packageName;
+ }
+ }
+
+ private void handleTaskStackChanged(ActivityManager.RunningTaskInfo frontTask) {
+ if (shouldPlayHomeSoundForCurrentTransition(frontTask)) {
mAudioManager.playSoundEffect(AudioManager.FX_HOME);
}
- mIsLastTaskHome = isCurrentTaskHome;
+ updateLastTaskInfo(frontTask);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index ddfa63a33149..709ccd4c2384 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -16,26 +16,18 @@
package com.android.systemui.wmshell;
-import static android.os.Process.THREAD_PRIORITY_DISPLAY;
-import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
-
-import android.animation.AnimationHandler;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.os.Handler;
-import android.os.HandlerThread;
import android.view.IWindowManager;
import android.view.WindowManager;
-import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.R;
import com.android.systemui.dagger.WMComponent;
import com.android.systemui.dagger.WMSingleton;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.FullscreenTaskListener;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellCommandHandler;
@@ -53,13 +45,11 @@ import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.FloatingContentCoordinator;
-import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
import com.android.wm.shell.common.annotations.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
@@ -99,110 +89,9 @@ import dagger.Provides;
* dependencies that are device/form factor SystemUI implementation specific should go into their
* respective modules (ie. {@link WMShellModule} for handheld, {@link TvWMShellModule} for tv, etc.)
*/
-@Module
+@Module(includes = WMShellConcurrencyModule.class)
public abstract class WMShellBaseModule {
- /**
- * Returns whether to enable a separate shell thread for the shell features.
- */
- private static boolean enableShellMainThread(Context context) {
- return context.getResources().getBoolean(R.bool.config_enableShellMainThread);
- }
-
- //
- // Shell Concurrency - Components used for managing threading in the Shell and SysUI
- //
-
- /**
- * Provide a SysUI main-thread Executor.
- */
- @WMSingleton
- @Provides
- @Main
- public static ShellExecutor provideSysUIMainExecutor(@Main Handler sysuiMainHandler) {
- return new HandlerExecutor(sysuiMainHandler);
- }
-
- /**
- * Shell main-thread Handler, don't use this unless really necessary (ie. need to dedupe
- * multiple types of messages, etc.)
- */
- @WMSingleton
- @Provides
- @ShellMainThread
- public static Handler provideShellMainHandler(Context context, @Main Handler sysuiMainHandler) {
- if (enableShellMainThread(context)) {
- HandlerThread mainThread = new HandlerThread("wmshell.main");
- mainThread.start();
- return mainThread.getThreadHandler();
- }
- return sysuiMainHandler;
- }
-
- /**
- * Provide a Shell main-thread Executor.
- */
- @WMSingleton
- @Provides
- @ShellMainThread
- public static ShellExecutor provideShellMainExecutor(Context context,
- @ShellMainThread Handler mainHandler, @Main ShellExecutor sysuiMainExecutor) {
- if (enableShellMainThread(context)) {
- return new HandlerExecutor(mainHandler);
- }
- return sysuiMainExecutor;
- }
-
- /**
- * Provide a Shell animation-thread Executor.
- */
- @WMSingleton
- @Provides
- @ShellAnimationThread
- public static ShellExecutor provideShellAnimationExecutor() {
- HandlerThread shellAnimationThread = new HandlerThread("wmshell.anim",
- THREAD_PRIORITY_DISPLAY);
- shellAnimationThread.start();
- return new HandlerExecutor(shellAnimationThread.getThreadHandler());
- }
-
- /**
- * Provides a Shell splashscreen-thread Executor
- */
- @WMSingleton
- @Provides
- @ShellSplashscreenThread
- public static ShellExecutor provideSplashScreenExecutor() {
- HandlerThread shellSplashscreenThread = new HandlerThread("wmshell.splashscreen",
- THREAD_PRIORITY_TOP_APP_BOOST);
- shellSplashscreenThread.start();
- return new HandlerExecutor(shellSplashscreenThread.getThreadHandler());
- }
-
- /**
- * Provide a Shell main-thread AnimationHandler. The AnimationHandler can be set on
- * {@link android.animation.ValueAnimator}s and will ensure that the animation will run on
- * the Shell main-thread with the SF vsync.
- */
- @WMSingleton
- @Provides
- @ChoreographerSfVsync
- public static AnimationHandler provideShellMainExecutorSfVsyncAnimationHandler(
- @ShellMainThread ShellExecutor mainExecutor) {
- try {
- AnimationHandler handler = new AnimationHandler();
- mainExecutor.executeBlocking(() -> {
- // This is called on the animation thread since it calls
- // Choreographer.getSfInstance() which returns a thread-local Choreographer instance
- // that uses the SF vsync
- handler.setProvider(new SfVsyncFrameCallbackProvider());
- });
- return handler;
- } catch (InterruptedException e) {
- throw new RuntimeException("Failed to initialize SfVsync animation handler in 1s", e);
- }
- }
-
//
// Internal common - Components used internally by multiple shell features
//
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellConcurrencyModule.java
new file mode 100644
index 000000000000..61f50b5aae30
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellConcurrencyModule.java
@@ -0,0 +1,163 @@
+/*
+ * 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.systemui.wmshell;
+
+import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
+
+import android.animation.AnimationHandler;
+import android.content.Context;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Trace;
+
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.systemui.R;
+import com.android.systemui.dagger.WMSingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.wm.shell.common.HandlerExecutor;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
+import com.android.wm.shell.common.annotations.ShellAnimationThread;
+import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Provides basic concurrency-related dependencies from {@link com.android.wm.shell}, these
+ * dependencies are only accessible from components within the WM subcomponent.
+ */
+@Module
+public abstract class WMShellConcurrencyModule {
+
+ private static final int MSGQ_SLOW_DELIVERY_THRESHOLD_MS = 30;
+ private static final int MSGQ_SLOW_DISPATCH_THRESHOLD_MS = 30;
+
+ /**
+ * Returns whether to enable a separate shell thread for the shell features.
+ */
+ private static boolean enableShellMainThread(Context context) {
+ return context.getResources().getBoolean(R.bool.config_enableShellMainThread);
+ }
+
+ //
+ // Shell Concurrency - Components used for managing threading in the Shell and SysUI
+ //
+
+ /**
+ * Provide a SysUI main-thread Executor.
+ */
+ @WMSingleton
+ @Provides
+ @Main
+ public static ShellExecutor provideSysUIMainExecutor(@Main Handler sysuiMainHandler) {
+ return new HandlerExecutor(sysuiMainHandler);
+ }
+
+ /**
+ * Shell main-thread Handler, don't use this unless really necessary (ie. need to dedupe
+ * multiple types of messages, etc.)
+ */
+ @WMSingleton
+ @Provides
+ @ShellMainThread
+ public static Handler provideShellMainHandler(Context context, @Main Handler sysuiMainHandler) {
+ if (enableShellMainThread(context)) {
+ HandlerThread mainThread = new HandlerThread("wmshell.main", THREAD_PRIORITY_DISPLAY);
+ mainThread.start();
+ if (Build.IS_DEBUGGABLE) {
+ mainThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER);
+ mainThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS,
+ MSGQ_SLOW_DELIVERY_THRESHOLD_MS);
+ }
+ return Handler.createAsync(mainThread.getLooper());
+ }
+ return sysuiMainHandler;
+ }
+
+ /**
+ * Provide a Shell main-thread Executor.
+ */
+ @WMSingleton
+ @Provides
+ @ShellMainThread
+ public static ShellExecutor provideShellMainExecutor(Context context,
+ @ShellMainThread Handler mainHandler, @Main ShellExecutor sysuiMainExecutor) {
+ if (enableShellMainThread(context)) {
+ return new HandlerExecutor(mainHandler);
+ }
+ return sysuiMainExecutor;
+ }
+
+ /**
+ * Provide a Shell animation-thread Executor.
+ */
+ @WMSingleton
+ @Provides
+ @ShellAnimationThread
+ public static ShellExecutor provideShellAnimationExecutor() {
+ HandlerThread shellAnimationThread = new HandlerThread("wmshell.anim",
+ THREAD_PRIORITY_DISPLAY);
+ shellAnimationThread.start();
+ if (Build.IS_DEBUGGABLE) {
+ shellAnimationThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER);
+ shellAnimationThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS,
+ MSGQ_SLOW_DELIVERY_THRESHOLD_MS);
+ }
+ return new HandlerExecutor(Handler.createAsync(shellAnimationThread.getLooper()));
+ }
+
+ /**
+ * Provides a Shell splashscreen-thread Executor
+ */
+ @WMSingleton
+ @Provides
+ @ShellSplashscreenThread
+ public static ShellExecutor provideSplashScreenExecutor() {
+ HandlerThread shellSplashscreenThread = new HandlerThread("wmshell.splashscreen",
+ THREAD_PRIORITY_TOP_APP_BOOST);
+ shellSplashscreenThread.start();
+ return new HandlerExecutor(shellSplashscreenThread.getThreadHandler());
+ }
+
+ /**
+ * Provide a Shell main-thread AnimationHandler. The AnimationHandler can be set on
+ * {@link android.animation.ValueAnimator}s and will ensure that the animation will run on
+ * the Shell main-thread with the SF vsync.
+ */
+ @WMSingleton
+ @Provides
+ @ChoreographerSfVsync
+ public static AnimationHandler provideShellMainExecutorSfVsyncAnimationHandler(
+ @ShellMainThread ShellExecutor mainExecutor) {
+ try {
+ AnimationHandler handler = new AnimationHandler();
+ mainExecutor.executeBlocking(() -> {
+ // This is called on the animation thread since it calls
+ // Choreographer.getSfInstance() which returns a thread-local Choreographer instance
+ // that uses the SF vsync
+ handler.setProvider(new SfVsyncFrameCallbackProvider());
+ });
+ return handler;
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Failed to initialize SfVsync animation handler in 1s", e);
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
index 3a77f7eec7f9..33a30e0bcc27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
@@ -21,16 +21,20 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
-import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.media.AudioManager;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -41,30 +45,50 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class HomeSoundEffectControllerTest extends SysuiTestCase {
- private @Mock Context mContext;
+ private static final String HOME_PACKAGE_NAME = "com.android.apps.home";
+ private static final String NON_HOME_PACKAGE_NAME = "com.android.apps.not.home";
+ private static final int HOME_TASK_ID = 0;
+ private static final int NON_HOME_TASK_ID = 1;
+
private @Mock AudioManager mAudioManager;
private @Mock TaskStackChangeListeners mTaskStackChangeListeners;
- private @Mock ActivityManager.RunningTaskInfo mStandardActivityTaskInfo;
- private @Mock ActivityManager.RunningTaskInfo mHomeActivityTaskInfo;
-
+ private @Mock ActivityManagerWrapper mActivityManagerWrapper;
+ private @Mock PackageManager mPackageManager;
+
+ private ActivityManager.RunningTaskInfo mTaskAStandardActivity;
+ private ActivityManager.RunningTaskInfo mTaskAExceptionActivity;
+ private ActivityManager.RunningTaskInfo mHomeTaskHomeActivity;
+ private ActivityManager.RunningTaskInfo mHomeTaskStandardActivity;
+ private ActivityManager.RunningTaskInfo mEmptyTask;
private HomeSoundEffectController mController;
private TaskStackChangeListener mTaskStackChangeListener;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
-
- doReturn(WindowConfiguration.ACTIVITY_TYPE_STANDARD).when(
- mStandardActivityTaskInfo).getActivityType();
- doReturn(WindowConfiguration.ACTIVITY_TYPE_HOME).when(
- mHomeActivityTaskInfo).getActivityType();
-
+ mTaskAStandardActivity = createRunningTaskInfo(NON_HOME_PACKAGE_NAME,
+ WindowConfiguration.ACTIVITY_TYPE_STANDARD, NON_HOME_TASK_ID,
+ true /* playHomeTransitionSound */);
+ mTaskAExceptionActivity = createRunningTaskInfo(NON_HOME_PACKAGE_NAME,
+ WindowConfiguration.ACTIVITY_TYPE_STANDARD, NON_HOME_TASK_ID,
+ false /* playHomeTransitionSound */);
+ mHomeTaskHomeActivity = createRunningTaskInfo(HOME_PACKAGE_NAME,
+ WindowConfiguration.ACTIVITY_TYPE_HOME, HOME_TASK_ID,
+ true /* playHomeTransitionSound */);
+ mHomeTaskStandardActivity = createRunningTaskInfo(HOME_PACKAGE_NAME,
+ WindowConfiguration.ACTIVITY_TYPE_STANDARD, HOME_TASK_ID,
+ true /* playHomeTransitionSound */);
+ mEmptyTask = new ActivityManager.RunningTaskInfo();
+ mContext.setMockPackageManager(mPackageManager);
+ when(mPackageManager.checkPermission(Manifest.permission.DISABLE_SYSTEM_SOUND_EFFECTS,
+ NON_HOME_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_GRANTED);
mController = new HomeSoundEffectController(mContext, mAudioManager,
- mTaskStackChangeListeners);
+ mTaskStackChangeListeners, mActivityManagerWrapper, mPackageManager);
}
@Test
@@ -73,43 +97,60 @@ public class HomeSoundEffectControllerTest extends SysuiTestCase {
startController(true /* isHomeSoundEffectEnabled */);
// And the home task moves to the front,
- mTaskStackChangeListener.onTaskMovedToFront(mHomeActivityTaskInfo);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(mHomeTaskHomeActivity);
+ mTaskStackChangeListener.onTaskStackChanged();
// Then no home sound effect should be played.
verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
}
+ /**
+ * Task A (playHomeTransitionSound = true) -> HOME
+ * Expectation: Home sound is played
+ */
@Test
public void testHomeSoundEffectPlayedWhenEnabled() {
// When HomeSoundEffectController is started and the home sound effect is enabled,
startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mHomeTaskHomeActivity);
// And first a task different from the home task moves to front,
- mTaskStackChangeListener.onTaskMovedToFront(mStandardActivityTaskInfo);
+ mTaskStackChangeListener.onTaskStackChanged();
// And the home task moves to the front,
- mTaskStackChangeListener.onTaskMovedToFront(mHomeActivityTaskInfo);
+ mTaskStackChangeListener.onTaskStackChanged();
// Then the home sound effect should be played.
verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
}
+ /**
+ * Task A (playHomeTransitionSound = true) -> HOME -> HOME
+ * Expectation: Home sound is played once after HOME moves to front the first time
+ */
@Test
public void testHomeSoundEffectNotPlayedTwiceInRow() {
// When HomeSoundEffectController is started and the home sound effect is enabled,
startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mHomeTaskHomeActivity,
+ mHomeTaskHomeActivity);
+
// And first a task different from the home task moves to front,
- mTaskStackChangeListener.onTaskMovedToFront(mStandardActivityTaskInfo);
+ mTaskStackChangeListener.onTaskStackChanged();
// And the home task moves to the front,
- mTaskStackChangeListener.onTaskMovedToFront(mHomeActivityTaskInfo);
+ mTaskStackChangeListener.onTaskStackChanged();
// Then the home sound effect should be played.
verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
// If the home task moves to front a second time in a row,
- mTaskStackChangeListener.onTaskMovedToFront(mHomeActivityTaskInfo);
+ mTaskStackChangeListener.onTaskStackChanged();
// Then no home sound effect should be played.
verify(mAudioManager, times(1)).playSoundEffect(AudioManager.FX_HOME);
@@ -121,7 +162,59 @@ public class HomeSoundEffectControllerTest extends SysuiTestCase {
startController(true /* isHomeSoundEffectEnabled */);
// And a standard, non-home task, moves to the front,
- mTaskStackChangeListener.onTaskMovedToFront(mStandardActivityTaskInfo);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(mTaskAStandardActivity);
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then no home sound effect should be played.
+ verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * Task A (playHomeTransitionSound = true) -> HOME -> HOME (activity type standard)
+ * Expectation: Home sound is played once after HOME moves to front
+ */
+ @Test
+ public void testHomeSoundEffectNotPlayedWhenOtherHomeActivityMovesToFront() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mHomeTaskHomeActivity,
+ mHomeTaskStandardActivity);
+
+ // And first a task different from the home task moves to front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then the home sound effect should be played.
+ verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
+
+ // If the home task moves to front a second time in a row,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then no home sound effect should be played.
+ verify(mAudioManager, times(1)).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * Task A (playHomeTransitionSound = true) -> HOME (activity type standard)
+ * Expectation: Home sound is not played
+ */
+ @Test
+ public void testHomeSoundEffectNotPlayedWhenOtherHomeActivityMovesToFrontOfOtherApp() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+
+ // And first a task different from the home task moves to front,
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mHomeTaskStandardActivity);
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And an activity from the home package but not the home root activity moves to front
+ mTaskStackChangeListener.onTaskStackChanged();
// Then no home sound effect should be played.
verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
@@ -138,6 +231,171 @@ public class HomeSoundEffectControllerTest extends SysuiTestCase {
}
/**
+ * Task A (playHomeTransitionSound = false) -> HOME
+ * Expectation: Home sound is not played
+ */
+ @Test
+ public void testHomeSoundEffectNotPlayedWhenHomeActivityMovesToFrontAfterException() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+
+ // And first a task different from the home task moves to front, which has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code>
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAExceptionActivity,
+ mHomeTaskHomeActivity);
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then no home sound effect should be played because the last package is an exception.
+ verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * HOME -> Task A (playHomeTransitionSound = true) -> Task A (playHomeTransitionSound = false)
+ * -> HOME
+ * Expectation: Home sound is not played
+ */
+ @Test
+ public void testHomeSoundEffectNotPlayedWhenHomeActivityMovesToFrontAfterException2() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mTaskAExceptionActivity,
+ mHomeTaskHomeActivity);
+
+ // And first a task different from the home task moves to front
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then a different activity from the same task moves to front, which has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code>
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then no home sound effect should be played.
+ verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * HOME -> Task A (playHomeTransitionSound = false) -> Task A (playHomeTransitionSound = true)
+ * -> HOME
+ * Expectation: Home sound is played
+ */
+ @Test
+ public void testHomeSoundEffectPlayedWhenHomeActivityMovesToFrontAfterException() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAExceptionActivity,
+ mTaskAStandardActivity,
+ mHomeTaskHomeActivity);
+
+ // And first a task different from the home task moves to front,
+ // the topActivity of this task has {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND}
+ // set to <code>false</code>
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then a different activity from the same task moves to front, which has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>true</code>
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then the home sound effect should be played.
+ verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * HOME -> Task A (playHomeTransitionSound = false) -> Task A (empty task, no top activity)
+ * -> HOME
+ * Expectation: Home sound is not played
+ */
+ @Test
+ public void testHomeSoundEffectNotPlayedWhenEmptyTaskMovesToFrontAfterException() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAExceptionActivity,
+ mEmptyTask,
+ mHomeTaskHomeActivity);
+
+ // And first a task different from the home task moves to front, whose topActivity has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code>
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then a task with no topActivity moves to front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then no home sound effect should be played.
+ verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * HOME -> Task A (playHomeTransitionSound = true) -> Task A (empty task, no top activity)
+ * -> HOME
+ * Expectation: Home sound is played
+ */
+ @Test
+ public void testHomeSoundEffectPlayedWhenEmptyTaskMovesToFrontAfterStandardActivity() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mEmptyTask,
+ mHomeTaskHomeActivity);
+
+ // And first a task different from the home task moves to front, whose topActivity has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code>
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then a task with no topActivity moves to front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then the home sound effect should be played.
+ verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * HOME -> Task A (playHomeTransitionSound = false, no permission) -> HOME
+ * Expectation: Home sound is played
+ */
+ @Test
+ public void testHomeSoundEffectPlayedWhenFlagSetButPermissionNotGranted() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mHomeTaskHomeActivity);
+ when(mPackageManager.checkPermission(Manifest.permission.DISABLE_SYSTEM_SOUND_EFFECTS,
+ NON_HOME_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_DENIED);
+
+ // And first a task different from the home task moves to front, whose topActivity has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>true</code>,
+ // but the app doesn't have the right permission granted
+ mTaskStackChangeListener.onTaskStackChanged();
+
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then the home sound effect should be played.
+ verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
* Sets {@link AudioManager#isHomeSoundEffectEnabled()} and starts HomeSoundEffectController.
* If the home sound effect is enabled, the registered TaskStackChangeListener is extracted.
*/
@@ -155,4 +413,20 @@ public class HomeSoundEffectControllerTest extends SysuiTestCase {
mTaskStackChangeListener = listenerCaptor.getValue();
}
}
+
+ private ActivityManager.RunningTaskInfo createRunningTaskInfo(String packageName,
+ int activityType, int taskId, boolean playHomeTransitionSound) {
+ ActivityManager.RunningTaskInfo res = new ActivityManager.RunningTaskInfo();
+ res.topActivityInfo = new ActivityInfo();
+ res.topActivityInfo.packageName = packageName;
+ res.topActivityType = activityType;
+ res.taskId = taskId;
+ if (!playHomeTransitionSound) {
+ // set the flag to 0
+ res.topActivityInfo.privateFlags &= ~ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND;
+ } else {
+ res.topActivityInfo.privateFlags |= ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND;
+ }
+ return res;
+ }
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d2fd8ff3890e..98931a528d31 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1790,6 +1790,44 @@ public final class ActiveServices {
}
if (!ignoreForeground) {
+ if (r.mStartForegroundCount == 0) {
+ /*
+ If the service was started with startService(), not
+ startForegroundService(), and if startForeground() isn't called within
+ mFgsStartForegroundTimeoutMs, then we check the state of the app
+ (who owns the service, which is the app that called startForeground())
+ again. If the app is in the foreground, or in any other cases where
+ FGS-starts are allowed, then we still allow the FGS to be started.
+ Otherwise, startForeground() would fail.
+
+ If the service was started with startForegroundService(), then the service
+ must call startForeground() within a timeout anyway, so we don't need this
+ check.
+ */
+ if (!r.fgRequired) {
+ final long delayMs = SystemClock.elapsedRealtime() - r.createRealTime;
+ if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
+ setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
+ r.appInfo.uid, r.intent.getIntent(), r, false);
+ final String temp = "startForegroundDelayMs:" + delayMs;
+ if (r.mInfoAllowStartForeground != null) {
+ r.mInfoAllowStartForeground += "; " + temp;
+ } else {
+ r.mInfoAllowStartForeground = temp;
+ }
+ r.mLoggedInfoAllowStartForeground = false;
+ }
+ }
+ } else if (r.mStartForegroundCount >= 1) {
+ // The second or later time startForeground() is called after service is
+ // started. Check for app state again.
+ final long delayMs = SystemClock.elapsedRealtime() -
+ r.mLastSetFgsRestrictionTime;
+ if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
+ setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
+ r.appInfo.uid, r.intent.getIntent(), r, false);
+ }
+ }
logFgsBackgroundStart(r);
if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) {
final String msg = "Service.startForeground() not allowed due to "
@@ -1843,6 +1881,7 @@ public final class ActiveServices {
active.mNumActive++;
}
r.isForeground = true;
+ r.mStartForegroundCount++;
if (!stopProcStatsOp) {
ServiceState stracker = r.getTracker();
if (stracker != null) {
@@ -1901,6 +1940,7 @@ public final class ActiveServices {
decActiveForegroundAppLocked(smap, r);
}
r.isForeground = false;
+ resetFgsRestrictionLocked(r);
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -3892,6 +3932,7 @@ public final class ActiveServices {
r.foregroundId = 0;
r.foregroundNoti = null;
r.mAllowWhileInUsePermissionInFgs = false;
+ r.mAllowStartForeground = REASON_DENIED;
// Clear start entries.
r.clearDeliveredStartsLocked();
@@ -5430,6 +5471,7 @@ public final class ActiveServices {
private void setFgsRestrictionLocked(String callingPackage,
int callingPid, int callingUid, Intent intent, ServiceRecord r,
boolean allowBackgroundActivityStarts) {
+ r.mLastSetFgsRestrictionTime = SystemClock.elapsedRealtime();
// Check DeviceConfig flag.
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
r.mAllowWhileInUsePermissionInFgs = true;
@@ -5450,6 +5492,15 @@ public final class ActiveServices {
}
}
+ void resetFgsRestrictionLocked(ServiceRecord r) {
+ r.mAllowWhileInUsePermissionInFgs = false;
+ r.mAllowStartForeground = REASON_DENIED;
+ r.mInfoAllowStartForeground = null;
+ r.mInfoTempFgsAllowListReason = null;
+ r.mLoggedInfoAllowStartForeground = false;
+ r.mLastSetFgsRestrictionTime = 0;
+ }
+
boolean canStartForegroundServiceLocked(int callingPid, int callingUid, String callingPackage) {
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
return true;
@@ -5601,6 +5652,7 @@ public final class ActiveServices {
+ ",callingUid:" + tempAllowListReason.mCallingUid))
+ ">"
+ "; targetSdkVersion:" + r.appInfo.targetSdkVersion
+ + "; startForegroundCount:" + r.mStartForegroundCount
+ "]";
if (!debugInfo.equals(r.mInfoAllowStartForeground)) {
r.mLoggedInfoAllowStartForeground = false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 5859cea2d284..f7abf6a3bfc2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -96,6 +96,7 @@ final class ActivityManagerConstants extends ContentObserver {
static final String KEY_PROCESS_CRASH_COUNT_LIMIT = "process_crash_count_limit";
static final String KEY_BOOT_TIME_TEMP_ALLOWLIST_DURATION = "boot_time_temp_allowlist_duration";
static final String KEY_FG_TO_BG_FGS_GRACE_DURATION = "fg_to_bg_fgs_grace_duration";
+ static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -135,7 +136,7 @@ final class ActivityManagerConstants extends ContentObserver {
private static final int DEFAULT_PROCESS_CRASH_COUNT_LIMIT = 12;
private static final int DEFAULT_BOOT_TIME_TEMP_ALLOWLIST_DURATION = 10 * 1000;
private static final long DEFAULT_FG_TO_BG_FGS_GRACE_DURATION = 5 * 1000;
-
+ private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000;
// Flag stored in the DeviceConfig API.
/**
@@ -396,6 +397,12 @@ final class ActivityManagerConstants extends ContentObserver {
*/
volatile long mFgToBgFgsGraceDuration = DEFAULT_FG_TO_BG_FGS_GRACE_DURATION;
+ /**
+ * When service started from background, before the timeout it can be promoted to FGS by calling
+ * Service.startForeground().
+ */
+ volatile long mFgsStartForegroundTimeoutMs = DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS;
+
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -586,6 +593,9 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_FG_TO_BG_FGS_GRACE_DURATION:
updateFgToBgFgsGraceDuration();
break;
+ case KEY_FGS_START_FOREGROUND_TIMEOUT:
+ updateFgsStartForegroundTimeout();
+ break;
default:
break;
}
@@ -869,6 +879,13 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_FG_TO_BG_FGS_GRACE_DURATION);
}
+ private void updateFgsStartForegroundTimeout() {
+ mFgsStartForegroundTimeoutMs = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_FGS_START_FOREGROUND_TIMEOUT,
+ DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS);
+ }
+
private void updateImperceptibleKillExemptions() {
IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.clear();
IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.addAll(mDefaultImperceptibleKillExemptPackages);
@@ -1071,6 +1088,8 @@ final class ActivityManagerConstants extends ContentObserver {
pw.println(mBootTimeTempAllowlistDuration);
pw.print(" "); pw.print(KEY_FG_TO_BG_FGS_GRACE_DURATION); pw.print("=");
pw.println(mFgToBgFgsGraceDuration);
+ pw.print(" "); pw.print(KEY_FGS_START_FOREGROUND_TIMEOUT); pw.print("=");
+ pw.println(mFgsStartForegroundTimeoutMs);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index e74c936af02d..5b2276ce250f 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -487,8 +487,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
Slog.wtf(TAG, "Error updating external stats: ", e);
}
- synchronized (BatteryExternalStatsWorker.this) {
- mLastCollectionTimeStamp = SystemClock.elapsedRealtime();
+ if ((updateFlags & UPDATE_ALL) == UPDATE_ALL) {
+ synchronized (BatteryExternalStatsWorker.this) {
+ mLastCollectionTimeStamp = SystemClock.elapsedRealtime();
+ }
}
}
};
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index c3f97adbd9c3..3b76021afc08 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -674,6 +674,13 @@ public final class BatteryStatsService extends IBatteryStats.Stub
public List<BatteryUsageStats> getBatteryUsageStats(List<BatteryUsageStatsQuery> queries) {
mContext.enforceCallingPermission(
android.Manifest.permission.BATTERY_STATS, null);
+ awaitCompletion();
+
+ if (mBatteryUsageStatsProvider.shouldUpdateStats(queries,
+ mWorker.getLastCollectionTimeStamp())) {
+ syncStats("get-stats", BatteryExternalStatsWorker.UPDATE_ALL);
+ }
+
return mBatteryUsageStatsProvider.getBatteryUsageStats(queries);
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 9cd9902f4995..54c35123fbb9 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -165,9 +165,16 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
// allow the service becomes foreground service? Service started from background may not be
// allowed to become a foreground service.
@PowerWhitelistManager.ReasonCode int mAllowStartForeground = REASON_DENIED;
+ // Debug info why mAllowStartForeground is allowed or denied.
String mInfoAllowStartForeground;
+ // Debug info if mAllowStartForeground is allowed because of a temp-allowlist.
FgsStartTempAllowList.TempFgsAllowListEntry mInfoTempFgsAllowListReason;
+ // Is the same mInfoAllowStartForeground string has been logged before? Used for dedup.
boolean mLoggedInfoAllowStartForeground;
+ // The number of times Service.startForeground() is called;
+ int mStartForegroundCount;
+ // Last time mAllowWhileInUsePermissionInFgs or mAllowStartForeground is set.
+ long mLastSetFgsRestrictionTime;
String stringName; // caching of toString
@@ -439,6 +446,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
pw.println(mRecentCallingUid);
pw.print(prefix); pw.print("allowStartForeground=");
pw.println(mAllowStartForeground);
+ pw.print(prefix); pw.print("startForegroundCount=");
+ pw.println(mStartForegroundCount);
pw.print(prefix); pw.print("infoAllowStartForeground=");
pw.println(mInfoAllowStartForeground);
if (delayed) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 143a1cf0e094..31183cac50e1 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1641,6 +1641,13 @@ class UserController implements Handler.Callback {
* PIN or pattern.
*/
private boolean maybeUnlockUser(final @UserIdInt int userId) {
+ if (mInjector.isFileEncryptedNativeOnly() && mLockPatternUtils.isSecure(userId)) {
+ // A token is needed, so don't bother trying to unlock without one.
+ // This keeps misleading error messages from being logged.
+ Slog.d(TAG, "Not unlocking user " + userId
+ + "'s CE storage yet because a credential token is needed");
+ return false;
+ }
// Try unlocking storage using empty token
return unlockUserCleared(userId, null, null, null);
}
@@ -3101,5 +3108,11 @@ class UserController implements Handler.Callback {
protected IStorageManager getStorageManager() {
return IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
}
+
+ // This is needed because isFileEncryptedNativeOnly is a static method,
+ // but it needs to be mocked out in tests.
+ protected boolean isFileEncryptedNativeOnly() {
+ return StorageManager.isFileEncryptedNativeOnly();
+ }
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 103ab957f312..a8cbcb5aa4f0 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -49,6 +49,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -633,7 +634,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
@Override
public void sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
- mQosCallbackTracker.sendEventQosSessionAvailable(qosCallbackId, session, attributes);
+ mQosCallbackTracker.sendEventEpsQosSessionAvailable(qosCallbackId, session, attributes);
+ }
+
+ @Override
+ public void sendNrQosSessionAvailable(final int qosCallbackId, final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ mQosCallbackTracker.sendEventNrQosSessionAvailable(qosCallbackId, session, attributes);
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
index 0f5400d0f8e6..534dbe7699a7 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
@@ -27,6 +27,7 @@ import android.net.QosSession;
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import java.util.Objects;
@@ -146,13 +147,23 @@ class QosCallbackAgentConnection implements IBinder.DeathRecipient {
mNetworkAgentInfo.onQosCallbackUnregistered(mAgentCallbackId);
}
- void sendEventQosSessionAvailable(final QosSession session,
+ void sendEventEpsQosSessionAvailable(final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
try {
- if (DBG) log("sendEventQosSessionAvailable: sending...");
+ if (DBG) log("sendEventEpsQosSessionAvailable: sending...");
mCallback.onQosEpsBearerSessionAvailable(session, attributes);
} catch (final RemoteException e) {
- loge("sendEventQosSessionAvailable: remote exception", e);
+ loge("sendEventEpsQosSessionAvailable: remote exception", e);
+ }
+ }
+
+ void sendEventNrQosSessionAvailable(final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ try {
+ if (DBG) log("sendEventNrQosSessionAvailable: sending...");
+ mCallback.onNrQosSessionAvailable(session, attributes);
+ } catch (final RemoteException e) {
+ loge("sendEventNrQosSessionAvailable: remote exception", e);
}
}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
index 8bda5323e4f8..b6ab47b276e3 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -27,6 +27,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import com.android.net.module.util.CollectionUtils;
@@ -179,17 +180,31 @@ public class QosCallbackTracker {
}
/**
- * Called when the NetworkAgent sends the qos session available event
+ * Called when the NetworkAgent sends the qos session available event for EPS
*
* @param qosCallbackId the callback id that the qos session is now available to
* @param session the qos session that is now available
* @param attributes the qos attributes that are now available on the qos session
*/
- public void sendEventQosSessionAvailable(final int qosCallbackId,
+ public void sendEventEpsQosSessionAvailable(final int qosCallbackId,
final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
- runOnAgentConnection(qosCallbackId, "sendEventQosSessionAvailable: ",
- ac -> ac.sendEventQosSessionAvailable(session, attributes));
+ runOnAgentConnection(qosCallbackId, "sendEventEpsQosSessionAvailable: ",
+ ac -> ac.sendEventEpsQosSessionAvailable(session, attributes));
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session available event for NR
+ *
+ * @param qosCallbackId the callback id that the qos session is now available to
+ * @param session the qos session that is now available
+ * @param attributes the qos attributes that are now available on the qos session
+ */
+ public void sendEventNrQosSessionAvailable(final int qosCallbackId,
+ final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ runOnAgentConnection(qosCallbackId, "sendEventNrQosSessionAvailable: ",
+ ac -> ac.sendEventNrQosSessionAvailable(session, attributes));
}
/**
diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
index 4f95d27a085e..75181307dc42 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -41,11 +41,11 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.SecureRandom;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.function.Supplier;
/**
* Manages set of updatable font files.
@@ -109,6 +109,7 @@ final class UpdatableFontDir {
private final FsverityUtil mFsverityUtil;
private final File mConfigFile;
private final File mTmpConfigFile;
+ private final Supplier<Long> mCurrentTimeSupplier;
private long mLastModifiedMillis;
private int mConfigVersion = 1;
@@ -128,18 +129,20 @@ final class UpdatableFontDir {
UpdatableFontDir(File filesDir, List<File> preinstalledFontDirs, FontFileParser parser,
FsverityUtil fsverityUtil) {
- this(filesDir, preinstalledFontDirs, parser, fsverityUtil, new File(CONFIG_XML_FILE));
+ this(filesDir, preinstalledFontDirs, parser, fsverityUtil, new File(CONFIG_XML_FILE),
+ () -> System.currentTimeMillis());
}
// For unit testing
UpdatableFontDir(File filesDir, List<File> preinstalledFontDirs, FontFileParser parser,
- FsverityUtil fsverityUtil, File configFile) {
+ FsverityUtil fsverityUtil, File configFile, Supplier<Long> currentTimeSupplier) {
mFilesDir = filesDir;
mPreinstalledFontDirs = preinstalledFontDirs;
mParser = parser;
mFsverityUtil = fsverityUtil;
mConfigFile = configFile;
mTmpConfigFile = new File(configFile.getAbsoluteFile() + ".tmp");
+ mCurrentTimeSupplier = currentTimeSupplier;
}
/* package */ void loadFontFileMap() {
@@ -209,7 +212,7 @@ final class UpdatableFontDir {
FileUtils.deleteContents(mFilesDir);
mFontFamilyMap.clear();
- mLastModifiedMillis = System.currentTimeMillis();
+ mLastModifiedMillis = mCurrentTimeSupplier.get();
try (FileOutputStream fos = new FileOutputStream(mConfigFile)) {
PersistentSystemFontConfig.writeToXml(fos, createPersistentConfig());
} catch (Exception e) {
@@ -245,7 +248,7 @@ final class UpdatableFontDir {
}
// Write config file.
- mLastModifiedMillis = Instant.now().getEpochSecond();
+ mLastModifiedMillis = mCurrentTimeSupplier.get();
try (FileOutputStream fos = new FileOutputStream(mTmpConfigFile)) {
PersistentSystemFontConfig.writeToXml(fos, createPersistentConfig());
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 4299d9e81915..385928525ada 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -422,8 +422,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final int MSG_LIMIT_REACHED = 5;
private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6;
private static final int MSG_ADVISE_PERSIST_THRESHOLD = 7;
- private static final int MSG_UPDATE_INTERFACE_QUOTA = 10;
- private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
+ private static final int MSG_UPDATE_INTERFACE_QUOTAS = 10;
+ private static final int MSG_REMOVE_INTERFACE_QUOTAS = 11;
private static final int MSG_POLICIES_CHANGED = 13;
private static final int MSG_RESET_FIREWALL_RULES_BY_UID = 15;
private static final int MSG_SUBSCRIPTION_OVERRIDE = 16;
@@ -2035,33 +2035,44 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED;
final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED;
long limitBytes = Long.MAX_VALUE;
- if (hasLimit && policy.hasCycle()) {
+ long warningBytes = Long.MAX_VALUE;
+ if ((hasLimit || hasWarning) && policy.hasCycle()) {
final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
.cycleIterator(policy).next();
final long start = cycle.first.toInstant().toEpochMilli();
final long end = cycle.second.toInstant().toEpochMilli();
final long totalBytes = getTotalBytes(policy.template, start, end);
- if (policy.lastLimitSnooze < start) {
+ // If the limit notification is not snoozed, the limit quota needs to be calculated.
+ if (hasLimit && policy.lastLimitSnooze < start) {
// remaining "quota" bytes are based on total usage in
// current cycle. kernel doesn't like 0-byte rules, so we
// set 1-byte quota and disable the radio later.
limitBytes = Math.max(1, policy.limitBytes - totalBytes);
}
+
+ // If the warning notification was snoozed by user, or the service already knows
+ // it is over warning bytes, doesn't need to calculate warning bytes.
+ if (hasWarning && policy.lastWarningSnooze < start
+ && !policy.isOverWarning(totalBytes)) {
+ warningBytes = Math.max(1, policy.warningBytes - totalBytes);
+ }
}
- if (hasLimit || policy.metered) {
+ if (hasWarning || hasLimit || policy.metered) {
if (matchingIfaces.size() > 1) {
// TODO: switch to shared quota once NMS supports
Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
}
- // Set the interface limit. For interfaces which has no cycle, or metered with
- // no policy limit, or snoozed limit notification; we still need to put iptables
- // rule hooks to restrict apps for data saver, so push really high quota.
+ // Set the interface warning and limit. For interfaces which has no cycle,
+ // or metered with no policy quotas, or snoozed notification; we still need to put
+ // iptables rule hooks to restrict apps for data saver, so push really high quota.
+ // TODO: Push NetworkStatsProvider.QUOTA_UNLIMITED instead of Long.MAX_VALUE to
+ // providers.
for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
final String iface = matchingIfaces.valueAt(j);
- setInterfaceQuotaAsync(iface, limitBytes);
+ setInterfaceQuotasAsync(iface, warningBytes, limitBytes);
newMeteredIfaces.add(iface);
}
}
@@ -2084,7 +2095,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
final String iface = matchingIfaces.valueAt(j);
if (!newMeteredIfaces.contains(iface)) {
- setInterfaceQuotaAsync(iface, Long.MAX_VALUE);
+ setInterfaceQuotasAsync(iface, Long.MAX_VALUE, Long.MAX_VALUE);
newMeteredIfaces.add(iface);
}
}
@@ -2096,7 +2107,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
final String iface = mMeteredIfaces.valueAt(i);
if (!newMeteredIfaces.contains(iface)) {
- removeInterfaceQuotaAsync(iface);
+ removeInterfaceQuotasAsync(iface);
}
}
mMeteredIfaces = newMeteredIfaces;
@@ -5036,19 +5047,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mNetworkStats.advisePersistThreshold(persistThreshold);
return true;
}
- case MSG_UPDATE_INTERFACE_QUOTA: {
- final String iface = (String) msg.obj;
- // int params need to be stitched back into a long
- final long quota = ((long) msg.arg1 << 32) | (msg.arg2 & 0xFFFFFFFFL);
- removeInterfaceQuota(iface);
- setInterfaceQuota(iface, quota);
- mNetworkStats.setStatsProviderLimitAsync(iface, quota);
+ case MSG_UPDATE_INTERFACE_QUOTAS: {
+ final IfaceQuotas val = (IfaceQuotas) msg.obj;
+ // TODO: Consider set a new limit before removing the original one.
+ removeInterfaceLimit(val.iface);
+ setInterfaceLimit(val.iface, val.limit);
+ mNetworkStats.setStatsProviderWarningAndLimitAsync(val.iface, val.warning,
+ val.limit);
return true;
}
- case MSG_REMOVE_INTERFACE_QUOTA: {
+ case MSG_REMOVE_INTERFACE_QUOTAS: {
final String iface = (String) msg.obj;
- removeInterfaceQuota(iface);
- mNetworkStats.setStatsProviderLimitAsync(iface, QUOTA_UNLIMITED);
+ removeInterfaceLimit(iface);
+ mNetworkStats.setStatsProviderWarningAndLimitAsync(iface, QUOTA_UNLIMITED,
+ QUOTA_UNLIMITED);
return true;
}
case MSG_RESET_FIREWALL_RULES_BY_UID: {
@@ -5196,15 +5208,32 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- private void setInterfaceQuotaAsync(String iface, long quotaBytes) {
- // long quotaBytes split up into two ints to fit in message
- mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTA, (int) (quotaBytes >> 32),
- (int) (quotaBytes & 0xFFFFFFFF), iface).sendToTarget();
+ private static final class IfaceQuotas {
+ @NonNull public final String iface;
+ // Warning and limit bytes of interface qutoas, could be QUOTA_UNLIMITED or Long.MAX_VALUE
+ // if not set. 0 is not acceptable since kernel doesn't like 0-byte rules.
+ public final long warning;
+ public final long limit;
+
+ private IfaceQuotas(@NonNull String iface, long warning, long limit) {
+ this.iface = iface;
+ this.warning = warning;
+ this.limit = limit;
+ }
+ }
+
+ private void setInterfaceQuotasAsync(@NonNull String iface,
+ long warningBytes, long limitBytes) {
+ mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTAS,
+ new IfaceQuotas(iface, warningBytes, limitBytes)).sendToTarget();
}
- private void setInterfaceQuota(String iface, long quotaBytes) {
+ private void setInterfaceLimit(String iface, long limitBytes) {
try {
- mNetworkManager.setInterfaceQuota(iface, quotaBytes);
+ // For legacy design the data warning is covered by global alert, where the
+ // kernel will notify upper layer for a small amount of change of traffic
+ // statistics. Thus, passing warning is not needed.
+ mNetworkManager.setInterfaceQuota(iface, limitBytes);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting interface quota", e);
} catch (RemoteException e) {
@@ -5212,11 +5241,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- private void removeInterfaceQuotaAsync(String iface) {
- mHandler.obtainMessage(MSG_REMOVE_INTERFACE_QUOTA, iface).sendToTarget();
+ private void removeInterfaceQuotasAsync(String iface) {
+ mHandler.obtainMessage(MSG_REMOVE_INTERFACE_QUOTAS, iface).sendToTarget();
}
- private void removeInterfaceQuota(String iface) {
+ private void removeInterfaceLimit(String iface) {
try {
mNetworkManager.removeInterfaceQuota(iface);
} catch (IllegalStateException e) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
index 0cb0bc2c0896..0e9a9da6804b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
@@ -37,8 +37,9 @@ public abstract class NetworkStatsManagerInternal {
public abstract void forceUpdate();
/**
- * Set the quota limit to all registered custom network stats providers.
+ * Set the warning and limit to all registered custom network stats providers.
* Note that invocation of any interface will be sent to all providers.
*/
- public abstract void setStatsProviderLimitAsync(@NonNull String iface, long quota);
+ public abstract void setStatsProviderWarningAndLimitAsync(@NonNull String iface, long warning,
+ long limit);
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 785e487ed10d..de5aae07d6be 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -1674,11 +1674,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
- public void setStatsProviderLimitAsync(@NonNull String iface, long quota) {
- if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")");
- // TODO: Set warning accordingly.
+ public void setStatsProviderWarningAndLimitAsync(
+ @NonNull String iface, long warning, long limit) {
+ if (LOGV) {
+ Slog.v(TAG, "setStatsProviderWarningAndLimitAsync("
+ + iface + "," + warning + "," + limit + ")");
+ }
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface,
- NetworkStatsProvider.QUOTA_UNLIMITED, quota));
+ warning, limit));
}
}
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 3bb5c1694734..3244c4400434 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -35,6 +35,7 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGR
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
@@ -1657,7 +1658,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
| FLAG_PERMISSION_USER_FIXED
| FLAG_PERMISSION_REVOKED_COMPAT
| FLAG_PERMISSION_REVIEW_REQUIRED
- | FLAG_PERMISSION_ONE_TIME;
+ | FLAG_PERMISSION_ONE_TIME
+ | FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY;
final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED
| FLAG_PERMISSION_POLICY_FIXED;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 8075bdb4f6f2..1b2ff08bb185 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -148,6 +148,8 @@ public class DomainVerificationService extends SystemService
@NonNull
private DomainVerificationProxy mProxy = new DomainVerificationProxyUnavailable();
+ private boolean mCanSendBroadcasts;
+
public DomainVerificationService(@NonNull Context context, @NonNull SystemConfig systemConfig,
@NonNull PlatformCompat platformCompat) {
super(context);
@@ -181,11 +183,18 @@ public class DomainVerificationService extends SystemService
@Override
public void onBootPhase(int phase) {
super.onBootPhase(phase);
- if (phase != SystemService.PHASE_BOOT_COMPLETED || !hasRealVerifier()) {
+ if (!hasRealVerifier()) {
return;
}
- verifyPackages(null, false);
+ switch (phase) {
+ case PHASE_ACTIVITY_MANAGER_READY:
+ mCanSendBroadcasts = true;
+ break;
+ case PHASE_BOOT_COMPLETED:
+ verifyPackages(null, false);
+ break;
+ }
}
@Override
@@ -858,7 +867,7 @@ public class DomainVerificationService extends SystemService
}
if (sendBroadcast) {
- sendBroadcastForPackage(pkgName);
+ sendBroadcast(pkgName);
}
}
@@ -937,7 +946,7 @@ public class DomainVerificationService extends SystemService
}
if (sendBroadcast && hasAutoVerifyDomains) {
- sendBroadcastForPackage(pkgName);
+ sendBroadcast(pkgName);
}
}
@@ -1098,8 +1107,19 @@ public class DomainVerificationService extends SystemService
return mCollector;
}
- private void sendBroadcastForPackage(@NonNull String packageName) {
- mProxy.sendBroadcastForPackages(Collections.singleton(packageName));
+ private void sendBroadcast(@NonNull String packageName) {
+ sendBroadcast(Collections.singleton(packageName));
+ }
+
+ private void sendBroadcast(@NonNull Set<String> packageNames) {
+ if (!mCanSendBroadcasts) {
+ // If the system cannot send broadcasts, it's probably still in boot, so dropping this
+ // request should be fine. The verification agent should re-scan packages once boot
+ // completes.
+ return;
+ }
+
+ mProxy.sendBroadcastForPackages(packageNames);
}
private boolean hasRealVerifier() {
@@ -1183,7 +1203,7 @@ public class DomainVerificationService extends SystemService
}
if (!packagesToBroadcast.isEmpty()) {
- mProxy.sendBroadcastForPackages(packagesToBroadcast);
+ sendBroadcast(packagesToBroadcast);
}
}
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 9bb2f041556a..94f8e59c6057 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1086,17 +1086,14 @@ int IncrementalService::makeFile(StorageId storage, std::string_view path, int m
return err;
}
if (params.size > 0) {
- // Only v2+ incfs supports automatically trimming file over-reserved sizes
- if (mIncFs->features() & incfs::Features::v2) {
- if (auto err = mIncFs->reserveSpace(ifs->control, normPath, params.size)) {
- if (err != -EOPNOTSUPP) {
- LOG(ERROR) << "Failed to reserve space for a new file: " << err;
- (void)mIncFs->unlink(ifs->control, normPath);
- return err;
- } else {
- LOG(WARNING) << "Reserving space for backing file isn't supported, "
- "may run out of disk later";
- }
+ if (auto err = mIncFs->reserveSpace(ifs->control, id, params.size)) {
+ if (err != -EOPNOTSUPP) {
+ LOG(ERROR) << "Failed to reserve space for a new file: " << err;
+ (void)mIncFs->unlink(ifs->control, normPath);
+ return err;
+ } else {
+ LOG(WARNING) << "Reserving space for backing file isn't supported, "
+ "may run out of disk later";
}
}
if (!data.empty()) {
@@ -1680,6 +1677,15 @@ void IncrementalService::runCmdLooper() {
}
}
+void IncrementalService::trimReservedSpaceV1(const IncFsMount& ifs) {
+ mIncFs->forEachFile(ifs.control, [this](auto&& control, auto&& fileId) {
+ if (mIncFs->isFileFullyLoaded(control, fileId) == incfs::LoadingState::Full) {
+ mIncFs->reserveSpace(control, fileId, -1);
+ }
+ return true;
+ });
+}
+
void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderParamsParcel&& params,
DataLoaderStatusListener&& statusListener,
const StorageHealthCheckParams& healthCheckParams,
@@ -1699,6 +1705,22 @@ void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderPara
std::move(statusListener), healthCheckParams,
std::move(healthListener), path::join(ifs.root, constants().mount));
+ // pre-v2 IncFS doesn't do automatic reserved space trimming - need to run it manually
+ if (!(mIncFs->features() & incfs::Features::v2)) {
+ addIfsStateCallback(ifs.mountId, [this](StorageId storageId, IfsState state) -> bool {
+ if (!state.fullyLoaded) {
+ return true;
+ }
+
+ const auto ifs = getIfs(storageId);
+ if (!ifs) {
+ return false;
+ }
+ trimReservedSpaceV1(*ifs);
+ return false;
+ });
+ }
+
addIfsStateCallback(ifs.mountId, [this](StorageId storageId, IfsState state) -> bool {
if (!state.fullyLoaded || state.readLogsEnabled) {
return true;
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index a697305457f8..fb6f56c9166e 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -452,6 +452,8 @@ private:
StorageLoadingProgressListener&& progressListener);
long getMillsSinceOldestPendingRead(StorageId storage);
+ void trimReservedSpaceV1(const IncFsMount& ifs);
+
private:
const std::unique_ptr<VoldServiceWrapper> mVold;
const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 34654994c9fc..8e416f36f49e 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -212,6 +212,9 @@ public:
std::string_view path) const final {
return incfs::isFullyLoaded(control, path);
}
+ incfs::LoadingState isFileFullyLoaded(const Control& control, FileId id) const final {
+ return incfs::isFullyLoaded(control, id);
+ }
incfs::LoadingState isEverythingFullyLoaded(const Control& control) const final {
return incfs::isEverythingFullyLoaded(control);
}
@@ -227,9 +230,8 @@ public:
ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const final {
return incfs::writeBlocks({blocks.data(), size_t(blocks.size())});
}
- ErrorCode reserveSpace(const Control& control, std::string_view path,
- IncFsSize size) const final {
- return incfs::reserveSpace(control, path, size);
+ ErrorCode reserveSpace(const Control& control, FileId id, IncFsSize size) const final {
+ return incfs::reserveSpace(control, id, size);
}
WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
std::vector<incfs::ReadInfo>* pendingReadsBuffer) const final {
@@ -238,19 +240,26 @@ public:
ErrorCode setUidReadTimeouts(const Control& control,
const std::vector<android::os::incremental::PerUidReadTimeouts>&
perUidReadTimeouts) const final {
- std::vector<incfs::UidReadTimeouts> timeouts;
- timeouts.resize(perUidReadTimeouts.size());
+ std::vector<incfs::UidReadTimeouts> timeouts(perUidReadTimeouts.size());
for (int i = 0, size = perUidReadTimeouts.size(); i < size; ++i) {
- auto&& timeout = timeouts[i];
+ auto& timeout = timeouts[i];
const auto& perUidTimeout = perUidReadTimeouts[i];
timeout.uid = perUidTimeout.uid;
timeout.minTimeUs = perUidTimeout.minTimeUs;
timeout.minPendingTimeUs = perUidTimeout.minPendingTimeUs;
timeout.maxPendingTimeUs = perUidTimeout.maxPendingTimeUs;
}
-
return incfs::setUidReadTimeouts(control, timeouts);
}
+ ErrorCode forEachFile(const Control& control, FileCallback cb) const final {
+ return incfs::forEachFile(control,
+ [&](auto& control, FileId id) { return cb(control, id); });
+ }
+ ErrorCode forEachIncompleteFile(const Control& control, FileCallback cb) const final {
+ return incfs::forEachIncompleteFile(control, [&](auto& control, FileId id) {
+ return cb(control, id);
+ });
+ }
};
static JNIEnv* getOrAttachJniEnv(JavaVM* jvm);
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index a787db573dfc..d4cdcbe9cac0 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -84,6 +84,8 @@ public:
void(std::string_view root, std::string_view backingDir,
std::span<std::pair<std::string_view, std::string_view>> binds)>;
+ using FileCallback = android::base::function_ref<bool(const Control& control, FileId fileId)>;
+
static std::string toString(FileId fileId);
virtual ~IncFsWrapper() = default;
@@ -105,14 +107,14 @@ public:
const Control& control, std::string_view path) const = 0;
virtual incfs::LoadingState isFileFullyLoaded(const Control& control,
std::string_view path) const = 0;
+ virtual incfs::LoadingState isFileFullyLoaded(const Control& control, FileId id) const = 0;
virtual incfs::LoadingState isEverythingFullyLoaded(const Control& control) const = 0;
virtual ErrorCode link(const Control& control, std::string_view from,
std::string_view to) const = 0;
virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0;
virtual UniqueFd openForSpecialOps(const Control& control, FileId id) const = 0;
virtual ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const = 0;
- virtual ErrorCode reserveSpace(const Control& control, std::string_view path,
- IncFsSize size) const = 0;
+ virtual ErrorCode reserveSpace(const Control& control, FileId id, IncFsSize size) const = 0;
virtual WaitResult waitForPendingReads(
const Control& control, std::chrono::milliseconds timeout,
std::vector<incfs::ReadInfo>* pendingReadsBuffer) const = 0;
@@ -120,6 +122,8 @@ public:
const Control& control,
const std::vector<::android::os::incremental::PerUidReadTimeouts>& perUidReadTimeouts)
const = 0;
+ virtual ErrorCode forEachFile(const Control& control, FileCallback cb) const = 0;
+ virtual ErrorCode forEachIncompleteFile(const Control& control, FileCallback cb) const = 0;
};
class AppOpsManagerWrapper {
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 8ba7c8686cba..ddb778462df5 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -379,6 +379,7 @@ public:
std::string_view path));
MOCK_CONST_METHOD2(isFileFullyLoaded,
incfs::LoadingState(const Control& control, std::string_view path));
+ MOCK_CONST_METHOD2(isFileFullyLoaded, incfs::LoadingState(const Control& control, FileId id));
MOCK_CONST_METHOD1(isEverythingFullyLoaded, incfs::LoadingState(const Control& control));
MOCK_CONST_METHOD3(link,
ErrorCode(const Control& control, std::string_view from,
@@ -386,14 +387,15 @@ public:
MOCK_CONST_METHOD2(unlink, ErrorCode(const Control& control, std::string_view path));
MOCK_CONST_METHOD2(openForSpecialOps, UniqueFd(const Control& control, FileId id));
MOCK_CONST_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks));
- MOCK_CONST_METHOD3(reserveSpace,
- ErrorCode(const Control& control, std::string_view path, IncFsSize size));
+ MOCK_CONST_METHOD3(reserveSpace, ErrorCode(const Control& control, FileId id, IncFsSize size));
MOCK_CONST_METHOD3(waitForPendingReads,
WaitResult(const Control& control, std::chrono::milliseconds timeout,
std::vector<incfs::ReadInfo>* pendingReadsBuffer));
MOCK_CONST_METHOD2(setUidReadTimeouts,
ErrorCode(const Control& control,
const std::vector<PerUidReadTimeouts>& perUidReadTimeouts));
+ MOCK_CONST_METHOD2(forEachFile, ErrorCode(const Control& control, FileCallback cb));
+ MOCK_CONST_METHOD2(forEachIncompleteFile, ErrorCode(const Control& control, FileCallback cb));
MockIncFs() {
ON_CALL(*this, listExistingMounts(_)).WillByDefault(Return());
@@ -1594,7 +1596,7 @@ TEST_F(IncrementalServiceTest, testIsFileFullyLoadedNoData) {
int storageId =
mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
IncrementalService::CreateOptions::CreateNew);
- EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
+ EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, An<std::string_view>()))
.Times(1)
.WillOnce(Return(incfs::LoadingState::MissingBlocks));
ASSERT_GT((int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"), 0);
@@ -1605,7 +1607,7 @@ TEST_F(IncrementalServiceTest, testIsFileFullyLoadedError) {
int storageId =
mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
IncrementalService::CreateOptions::CreateNew);
- EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
+ EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, An<std::string_view>()))
.Times(1)
.WillOnce(Return(incfs::LoadingState(-1)));
ASSERT_LT((int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"), 0);
@@ -1616,7 +1618,7 @@ TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccess) {
int storageId =
mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
IncrementalService::CreateOptions::CreateNew);
- EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
+ EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, An<std::string_view>()))
.Times(1)
.WillOnce(Return(incfs::LoadingState::Full));
ASSERT_EQ(0, (int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index a262939c0ef9..29aedcea0cd2 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -295,10 +295,30 @@ public final class ProfcollectForwardingService extends SystemService {
return;
}
- try {
- mIProfcollect.report();
- } catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
- }
+ final boolean uploadReport =
+ DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
+ "upload_report", false);
+
+ new Thread(() -> {
+ try {
+ String reportPath = mIProfcollect.report();
+ if (!uploadReport) {
+ return;
+ }
+ Intent uploadIntent =
+ new Intent("com.google.android.apps.betterbug.intent.action.UPLOAD_PROFILE")
+ .setPackage("com.google.android.apps.internal.betterbug")
+ .putExtra("EXTRA_DESTINATION", "PROFCOLLECT")
+ .putExtra("EXTRA_PACKAGE_NAME", getContext().getPackageName())
+ .putExtra("EXTRA_PROFILE_PATH", reportPath)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ Context context = getContext();
+ if (context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0) != null) {
+ context.sendBroadcast(uploadIntent);
+ }
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, e.getMessage());
+ }
+ }).start();
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index 22b2f7e04069..d220444f47de 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -1015,7 +1015,7 @@ public class ApplicationExitInfoTest {
assertNotNull(info);
if (timestamp != null) {
- final long tolerance = 1000; // ms
+ final long tolerance = 10000; // ms
assertTrue(timestamp - tolerance <= info.getTimestamp());
assertTrue(timestamp + tolerance >= info.getTimestamp());
}
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 9ffb50176f0e..5c8a7d25a25d 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -80,6 +80,7 @@ import android.util.Log;
import androidx.test.filters.SmallTest;
+import com.android.internal.widget.LockPatternUtils;
import com.android.server.FgThread;
import com.android.server.am.UserState.KeyEvictedCallback;
import com.android.server.pm.UserManagerInternal;
@@ -123,6 +124,7 @@ public class UserControllerTest {
private static final long HANDLER_WAIT_TIME_MS = 100;
private UserController mUserController;
+ private LockPatternUtils mLockPatternUtils;
private TestInjector mInjector;
private final HashMap<Integer, UserState> mUserStates = new HashMap<>();
@@ -161,6 +163,13 @@ public class UserControllerTest {
doNothing().when(mInjector).activityManagerOnUserStopped(anyInt());
doNothing().when(mInjector).clearBroadcastQueueForUser(anyInt());
doNothing().when(mInjector).taskSupervisorRemoveUser(anyInt());
+
+ // Make it appear that calling unlockUserKey() is needed.
+ doReturn(true).when(mInjector).isFileEncryptedNativeOnly();
+ mLockPatternUtils = mock(LockPatternUtils.class);
+ when(mLockPatternUtils.isSecure(anyInt())).thenReturn(false);
+ doReturn(mLockPatternUtils).when(mInjector).getLockPatternUtils();
+
// All UserController params are set to default.
mUserController = new UserController(mInjector);
setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS);
@@ -552,6 +561,20 @@ public class UserControllerTest {
/* keyEvictedCallback= */ mKeyEvictedCallback, /* expectLocking= */ true);
}
+ /**
+ * Test that if a user has a lock screen credential set, then UserController
+ * doesn't bother trying to unlock their storage key without a credential
+ * token, as it will never work.
+ */
+ @Test
+ public void testSecureUserUnlockNotAttempted() throws Exception {
+ when(mLockPatternUtils.isSecure(eq(TEST_USER_ID1))).thenReturn(true);
+ setUpUser(TEST_USER_ID1, 0);
+ mUserController.startUser(TEST_USER_ID1, /* foreground= */ false);
+ verify(mInjector.mStorageManagerMock, times(0))
+ .unlockUserKey(eq(TEST_USER_ID1), anyInt(), any(), any());
+ }
+
@Test
public void testStartProfile_fullUserFails() {
setUpUser(TEST_USER_ID1, 0);
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
index dbb415c88a5f..e7ffea0a650d 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
@@ -54,6 +54,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
@Presubmit
@@ -117,10 +118,13 @@ public final class UpdatableFontDirTest {
}
}
+ private static final long CURRENT_TIME = 1234567890L;
+
private File mCacheDir;
private File mUpdatableFontFilesDir;
private File mConfigFile;
private List<File> mPreinstalledFontDirs;
+ private Supplier<Long> mCurrentTimeSupplier = () -> CURRENT_TIME;
@SuppressWarnings("ResultOfMethodCallIgnored")
@Before
@@ -147,7 +151,7 @@ public final class UpdatableFontDirTest {
@Test
public void construct() throws Exception {
- long expectedModifiedDate = 1234567890;
+ long expectedModifiedDate = CURRENT_TIME / 2;
FakeFontFileParser parser = new FakeFontFileParser();
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
@@ -155,7 +159,7 @@ public final class UpdatableFontDirTest {
writeConfig(config, mConfigFile);
UpdatableFontDir dirForPreparation = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dirForPreparation.loadFontFileMap();
assertThat(dirForPreparation.getSystemFontConfig().getLastModifiedTimeMillis())
.isEqualTo(expectedModifiedDate);
@@ -168,6 +172,9 @@ public final class UpdatableFontDirTest {
+ " <font>foo.ttf</font>"
+ " <font>bar.ttf</font>"
+ "</family>")));
+ // Verifies that getLastModifiedTimeMillis() returns the value of currentTimeMillis.
+ assertThat(dirForPreparation.getSystemFontConfig().getLastModifiedTimeMillis())
+ .isEqualTo(CURRENT_TIME);
// Four font dirs are created.
assertThat(mUpdatableFontFilesDir.list()).hasLength(4);
assertThat(dirForPreparation.getSystemFontConfig().getLastModifiedTimeMillis())
@@ -175,7 +182,7 @@ public final class UpdatableFontDirTest {
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
assertThat(dir.getFontFileMap()).containsKey("foo.ttf");
assertThat(parser.getRevision(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(3);
@@ -199,7 +206,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
assertThat(dir.getFontFileMap()).isEmpty();
assertThat(dir.getFontFamilyMap()).isEmpty();
@@ -211,7 +218,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dirForPreparation = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dirForPreparation.loadFontFileMap();
dirForPreparation.update(Arrays.asList(
newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
@@ -229,7 +236,7 @@ public final class UpdatableFontDirTest {
dirForPreparation.getFontFileMap().get("foo.ttf").getAbsolutePath());
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
assertThat(dir.getFontFileMap()).isEmpty();
// All font dirs (including dir for "bar.ttf") should be deleted.
@@ -243,7 +250,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dirForPreparation = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dirForPreparation.loadFontFileMap();
dirForPreparation.update(Arrays.asList(
newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
@@ -262,7 +269,7 @@ public final class UpdatableFontDirTest {
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
assertThat(dir.getFontFileMap()).isEmpty();
// All font dirs (including dir for "bar.ttf") should be deleted.
@@ -276,7 +283,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dirForPreparation = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dirForPreparation.loadFontFileMap();
dirForPreparation.update(Arrays.asList(
newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
@@ -296,7 +303,7 @@ public final class UpdatableFontDirTest {
FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(1), "bar.ttf"), "bar,2");
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
// For foo.ttf, preinstalled font (revision 5) should be used.
assertThat(dir.getFontFileMap()).doesNotContainKey("foo.ttf");
@@ -317,7 +324,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- new File("/dev/null"));
+ new File("/dev/null"), mCurrentTimeSupplier);
dir.loadFontFileMap();
assertThat(dir.getFontFileMap()).isEmpty();
assertThat(dir.getFontFamilyMap()).isEmpty();
@@ -329,7 +336,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dirForPreparation = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dirForPreparation.loadFontFileMap();
dirForPreparation.update(Arrays.asList(
newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
@@ -351,7 +358,7 @@ public final class UpdatableFontDirTest {
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
// The state should be rolled back as a whole if one of the update requests fail.
assertThat(dir.getFontFileMap()).containsKey("foo.ttf");
@@ -369,7 +376,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE)));
@@ -387,7 +394,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE)));
@@ -406,7 +413,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,2", GOOD_SIGNATURE)));
@@ -428,7 +435,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE)));
@@ -445,7 +452,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
dir.update(Arrays.asList(
@@ -463,7 +470,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
try {
@@ -485,7 +492,7 @@ public final class UpdatableFontDirTest {
FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test.ttf,1");
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
try {
@@ -517,7 +524,7 @@ public final class UpdatableFontDirTest {
try {
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- readonlyFile);
+ readonlyFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
try {
@@ -551,7 +558,7 @@ public final class UpdatableFontDirTest {
public long getRevision(File file) throws IOException {
return 0;
}
- }, fakeFsverityUtil, mConfigFile);
+ }, fakeFsverityUtil, mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
try {
@@ -580,7 +587,7 @@ public final class UpdatableFontDirTest {
public long getRevision(File file) throws IOException {
return 0;
}
- }, fakeFsverityUtil, mConfigFile);
+ }, fakeFsverityUtil, mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
try {
@@ -617,7 +624,7 @@ public final class UpdatableFontDirTest {
FakeFontFileParser parser = new FakeFontFileParser();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
try {
@@ -637,7 +644,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE)));
@@ -660,7 +667,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
dir.update(Arrays.asList(
@@ -682,7 +689,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
try {
@@ -703,7 +710,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
try {
@@ -723,7 +730,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
// We assume we have monospace.
assertNamedFamilyExists(dir.getSystemFontConfig(), "monospace");
@@ -755,7 +762,7 @@ public final class UpdatableFontDirTest {
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
- mConfigFile);
+ mConfigFile, mCurrentTimeSupplier);
dir.loadFontFileMap();
assertThat(dir.getSystemFontConfig().getFontFamilies()).isNotEmpty();
FontConfig.FontFamily firstFontFamily = dir.getSystemFontConfig().getFontFamilies().get(0);
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index d405113d064c..100d3ea87a89 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -1773,57 +1773,75 @@ public class NetworkPolicyManagerServiceTest {
true);
}
+ private void increaseMockedTotalBytes(NetworkStats stats, long rxBytes, long txBytes) {
+ stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
+ rxBytes, 1, txBytes, 1, 0);
+ when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
+ .thenReturn(stats.getTotalBytes());
+ when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
+ .thenReturn(stats);
+ }
+
+ private void triggerOnStatsProviderWarningOrLimitReached() throws InterruptedException {
+ final NetworkPolicyManagerInternal npmi = LocalServices
+ .getService(NetworkPolicyManagerInternal.class);
+ npmi.onStatsProviderWarningOrLimitReached("TEST");
+ // Wait for processing of MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED.
+ postMsgAndWaitForCompletion();
+ verify(mStatsService).forceUpdate();
+ // Wait for processing of MSG_*_INTERFACE_QUOTAS.
+ postMsgAndWaitForCompletion();
+ }
+
/**
- * Test that when StatsProvider triggers limit reached, new limit will be calculated and
- * re-armed.
+ * Test that when StatsProvider triggers warning and limit reached, new quotas will be
+ * calculated and re-armed.
*/
@Test
- public void testStatsProviderLimitReached() throws Exception {
+ public void testStatsProviderWarningAndLimitReached() throws Exception {
final int CYCLE_DAY = 15;
final NetworkStats stats = new NetworkStats(0L, 1);
- stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
- 2999, 1, 2000, 1, 0);
- when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
- .thenReturn(stats.getTotalBytes());
- when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
- .thenReturn(stats);
+ increaseMockedTotalBytes(stats, 2999, 2000);
// Get active mobile network in place
expectMobileDefaults();
mService.updateNetworks();
- verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, Long.MAX_VALUE);
+ verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE,
+ Long.MAX_VALUE);
- // Set limit to 10KB.
+ // Set warning to 7KB and limit to 10KB.
setNetworkPolicies(new NetworkPolicy(
- sTemplateMobileAll, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, 10000L,
- true));
+ sTemplateMobileAll, CYCLE_DAY, TIMEZONE_UTC, 7000L, 10000L, true));
postMsgAndWaitForCompletion();
- // Verifies that remaining quota is set to providers.
- verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, 10000L - 4999L);
-
+ // Verifies that remaining quotas are set to providers.
+ verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2001L, 5001L);
reset(mStatsService);
- // Increase the usage.
- stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
- 1000, 1, 999, 1, 0);
- when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
- .thenReturn(stats.getTotalBytes());
- when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
- .thenReturn(stats);
+ // Increase the usage and simulates that limit reached fires earlier by provider,
+ // but actually the quota is not yet reached. Verifies that the limit reached leads to
+ // a force update and new quotas should be set.
+ increaseMockedTotalBytes(stats, 1000, 999);
+ triggerOnStatsProviderWarningOrLimitReached();
+ verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2L, 3002L);
+ reset(mStatsService);
- // Simulates that limit reached fires earlier by provider, but actually the quota is not
- // yet reached.
- final NetworkPolicyManagerInternal npmi = LocalServices
- .getService(NetworkPolicyManagerInternal.class);
- npmi.onStatsProviderWarningOrLimitReached("TEST");
+ // Increase the usage and simulate warning reached, the new warning should be unlimited
+ // since service will disable warning quota to stop lower layer from keep triggering
+ // warning reached event.
+ increaseMockedTotalBytes(stats, 1000L, 1000);
+ triggerOnStatsProviderWarningOrLimitReached();
+ verify(mStatsService).setStatsProviderWarningAndLimitAsync(
+ TEST_IFACE, Long.MAX_VALUE, 1002L);
+ reset(mStatsService);
- // Verifies that the limit reached leads to a force update and new limit should be set.
- postMsgAndWaitForCompletion();
- verify(mStatsService).forceUpdate();
- postMsgAndWaitForCompletion();
- verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, 10000L - 4999L - 1999L);
+ // Increase the usage that over the warning and limit, the new limit should set to 1 to
+ // block the network traffic.
+ increaseMockedTotalBytes(stats, 1000L, 1000);
+ triggerOnStatsProviderWarningOrLimitReached();
+ verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE, 1L);
+ reset(mStatsService);
}
/**
diff --git a/telephony/java/android/telephony/data/NrQos.java b/telephony/java/android/telephony/data/NrQos.java
index 2011eed26977..fe124ac15393 100644
--- a/telephony/java/android/telephony/data/NrQos.java
+++ b/telephony/java/android/telephony/data/NrQos.java
@@ -50,6 +50,18 @@ public final class NrQos extends Qos implements Parcelable {
return new NrQos(in);
}
+ public int get5Qi() {
+ return fiveQi;
+ }
+
+ public int getQfi() {
+ return qosFlowId;
+ }
+
+ public int getAveragingWindow() {
+ return averagingWindowMs;
+ }
+
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(Qos.QOS_TYPE_NR, dest, flags);
diff --git a/telephony/java/android/telephony/data/NrQosSessionAttributes.aidl b/telephony/java/android/telephony/data/NrQosSessionAttributes.aidl
new file mode 100644
index 000000000000..fd3bbb0865cb
--- /dev/null
+++ b/telephony/java/android/telephony/data/NrQosSessionAttributes.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package android.telephony.data;
+
+ parcelable NrQosSessionAttributes;
diff --git a/telephony/java/android/telephony/data/NrQosSessionAttributes.java b/telephony/java/android/telephony/data/NrQosSessionAttributes.java
new file mode 100644
index 000000000000..857ccb960d52
--- /dev/null
+++ b/telephony/java/android/telephony/data/NrQosSessionAttributes.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.QosSessionAttributes;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides Qos attributes of an NR bearer.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class NrQosSessionAttributes implements Parcelable, QosSessionAttributes {
+ private static final String TAG = NrQosSessionAttributes.class.getSimpleName();
+ private final int m5Qi;
+ private final int mQfi;
+ private final long mMaxUplinkBitRate;
+ private final long mMaxDownlinkBitRate;
+ private final long mGuaranteedUplinkBitRate;
+ private final long mGuaranteedDownlinkBitRate;
+ private final long mAveragingWindow;
+ @NonNull private final List<InetSocketAddress> mRemoteAddresses;
+
+ /**
+ * 5G QOS Identifier (5QI), see 3GPP TS 24.501 and 23.501.
+ * The allowed values are standard values(1-9, 65-68, 69-70, 75, 79-80, 82-85)
+ * defined in the spec and operator specific values in the range 128-254.
+ *
+ * @return the 5QI of the QOS flow
+ */
+ public int get5Qi() {
+ return m5Qi;
+ }
+
+ /**
+ * QOS flow identifier of the QOS flow description in the
+ * range of 1 to 63. see 3GPP TS 24.501 and 23.501.
+ *
+ * @return the QOS flow identifier of the session
+ */
+ public int getQfi() {
+ return mQfi;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the uplink.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedUplinkBitRate() {
+ return mGuaranteedUplinkBitRate;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the downlink.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedDownlinkBitRate() {
+ return mGuaranteedDownlinkBitRate;
+ }
+
+ /**
+ * The maximum uplink kbps that the network will accept.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max uplink bit rate in kbps
+ */
+ public long getMaxUplinkBitRate() {
+ return mMaxUplinkBitRate;
+ }
+
+ /**
+ * The maximum downlink kbps that the network can provide.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max downlink bit rate in kbps
+ */
+ public long getMaxDownlinkBitRate() {
+ return mMaxDownlinkBitRate;
+ }
+
+ /**
+ * The duration in milliseconds over which the maximum bit rates and guaranteed bit rates
+ * are calculated
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * @return the averaging window duration in milliseconds
+ */
+ public long getAveragingWindow() {
+ return mAveragingWindow;
+ }
+
+ /**
+ * List of remote addresses associated with the Qos Session. The given uplink bit rates apply
+ * to this given list of remote addresses.
+ *
+ * Note: In the event that the list is empty, it is assumed that the uplink bit rates apply to
+ * all remote addresses that are not contained in a different set of attributes.
+ *
+ * @return list of remote socket addresses that the attributes apply to
+ */
+ @NonNull
+ public List<InetSocketAddress> getRemoteAddresses() {
+ return mRemoteAddresses;
+ }
+
+ /**
+ * ..ctor for attributes
+ *
+ * @param fiveQi 5G quality class indicator
+ * @param qfi QOS flow identifier
+ * @param maxDownlinkBitRate the max downlink bit rate in kbps
+ * @param maxUplinkBitRate the max uplink bit rate in kbps
+ * @param guaranteedDownlinkBitRate the guaranteed downlink bit rate in kbps
+ * @param guaranteedUplinkBitRate the guaranteed uplink bit rate in kbps
+ * @param averagingWindow the averaging window duration in milliseconds
+ * @param remoteAddresses the remote addresses that the uplink bit rates apply to
+ *
+ * @hide
+ */
+ public NrQosSessionAttributes(final int fiveQi, final int qfi,
+ final long maxDownlinkBitRate, final long maxUplinkBitRate,
+ final long guaranteedDownlinkBitRate, final long guaranteedUplinkBitRate,
+ final long averagingWindow, @NonNull final List<InetSocketAddress> remoteAddresses) {
+ Objects.requireNonNull(remoteAddresses, "remoteAddress must be non-null");
+ m5Qi = fiveQi;
+ mQfi = qfi;
+ mMaxDownlinkBitRate = maxDownlinkBitRate;
+ mMaxUplinkBitRate = maxUplinkBitRate;
+ mGuaranteedDownlinkBitRate = guaranteedDownlinkBitRate;
+ mGuaranteedUplinkBitRate = guaranteedUplinkBitRate;
+ mAveragingWindow = averagingWindow;
+
+ final List<InetSocketAddress> remoteAddressesTemp = copySocketAddresses(remoteAddresses);
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddressesTemp);
+ }
+
+ private static List<InetSocketAddress> copySocketAddresses(
+ @NonNull final List<InetSocketAddress> remoteAddresses) {
+ final List<InetSocketAddress> remoteAddressesTemp = new ArrayList<>();
+ for (final InetSocketAddress socketAddress : remoteAddresses) {
+ if (socketAddress != null && socketAddress.getAddress() != null) {
+ remoteAddressesTemp.add(socketAddress);
+ }
+ }
+ return remoteAddressesTemp;
+ }
+
+ private NrQosSessionAttributes(@NonNull final Parcel in) {
+ m5Qi = in.readInt();
+ mQfi = in.readInt();
+ mMaxDownlinkBitRate = in.readLong();
+ mMaxUplinkBitRate = in.readLong();
+ mGuaranteedDownlinkBitRate = in.readLong();
+ mGuaranteedUplinkBitRate = in.readLong();
+ mAveragingWindow = in.readLong();
+
+ final int size = in.readInt();
+ final List<InetSocketAddress> remoteAddresses = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ final byte[] addressBytes = in.createByteArray();
+ final int port = in.readInt();
+ try {
+ remoteAddresses.add(
+ new InetSocketAddress(InetAddress.getByAddress(addressBytes), port));
+ } catch (final UnknownHostException e) {
+ // Impossible case since its filtered out the null values in the ..ctor
+ Log.e(TAG, "unable to unparcel remote address at index: " + i, e);
+ }
+ }
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddresses);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeInt(m5Qi);
+ dest.writeInt(mQfi);
+ dest.writeLong(mMaxDownlinkBitRate);
+ dest.writeLong(mMaxUplinkBitRate);
+ dest.writeLong(mGuaranteedDownlinkBitRate);
+ dest.writeLong(mGuaranteedUplinkBitRate);
+ dest.writeLong(mAveragingWindow);
+
+ final int size = mRemoteAddresses.size();
+ dest.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ final InetSocketAddress address = mRemoteAddresses.get(i);
+ dest.writeByteArray(address.getAddress().getAddress());
+ dest.writeInt(address.getPort());
+ }
+ }
+
+ @NonNull
+ public static final Creator<NrQosSessionAttributes> CREATOR =
+ new Creator<NrQosSessionAttributes>() {
+ @NonNull
+ @Override
+ public NrQosSessionAttributes createFromParcel(@NonNull final Parcel in) {
+ return new NrQosSessionAttributes(in);
+ }
+
+ @NonNull
+ @Override
+ public NrQosSessionAttributes[] newArray(final int size) {
+ return new NrQosSessionAttributes[size];
+ }
+ };
+}
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
index f49d4fcab5f2..4259a8620727 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
@@ -32,7 +32,7 @@ public class HierrarchicalDataClassBase implements Parcelable {
- // Code below generated by codegen v1.0.20.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -98,8 +98,8 @@ public class HierrarchicalDataClassBase implements Parcelable {
};
@DataClass.Generated(
- time = 1604522375155L,
- codegenVersion = "1.0.20",
+ time = 1616541542813L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java",
inputSignatures = "private int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
index e8cce23fa324..677094b14fd6 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
@@ -46,7 +46,7 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
- // Code below generated by codegen v1.0.20.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -120,8 +120,8 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
};
@DataClass.Generated(
- time = 1604522376059L,
- codegenVersion = "1.0.20",
+ time = 1616541543730L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java",
inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
index 9de65522fccd..eb260ab6d35d 100644
--- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
@@ -54,7 +54,7 @@ public class ParcelAllTheThingsDataClass implements Parcelable {
- // Code below generated by codegen v1.0.20.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -412,8 +412,8 @@ public class ParcelAllTheThingsDataClass implements Parcelable {
}
@DataClass.Generated(
- time = 1604522374190L,
- codegenVersion = "1.0.20",
+ time = 1616541541942L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java",
inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index 5a3e273275ed..158e0656b574 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -23,8 +23,11 @@ import android.annotation.Size;
import android.annotation.StringDef;
import android.annotation.StringRes;
import android.annotation.UserIdInt;
+import android.companion.ICompanionDeviceManager;
import android.content.pm.PackageManager;
import android.net.LinkAddress;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -282,6 +285,16 @@ public final class SampleDataClass implements Parcelable {
/**
+ * Binder types are also supported
+ */
+ private @NonNull IBinder mToken = new Binder();
+ /**
+ * AIDL interface types are also supported
+ */
+ private @Nullable ICompanionDeviceManager mIPCInterface = null;
+
+
+ /**
* Manually declaring any method that would otherwise be generated suppresses its generation,
* allowing for fine-grained overrides of the generated behavior.
*/
@@ -344,7 +357,7 @@ public final class SampleDataClass implements Parcelable {
- // Code below generated by codegen v1.0.20.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -492,6 +505,10 @@ public final class SampleDataClass implements Parcelable {
*
* Validation annotations following {@link Each} annotation, will be applied for each
* array/collection element instead.
+ * @param token
+ * Binder types are also supported
+ * @param iPCInterface
+ * AIDL interface types are also supported
*/
@DataClass.Generated.Member
public SampleDataClass(
@@ -514,7 +531,9 @@ public final class SampleDataClass implements Parcelable {
@Nullable LinkAddress[] linkAddresses5,
@StringRes int stringRes,
@android.annotation.IntRange(from = 0, to = 6) int dayOfWeek,
- @Size(2) @NonNull @FloatRange(from = 0f) float[] coords) {
+ @Size(2) @NonNull @FloatRange(from = 0f) float[] coords,
+ @NonNull IBinder token,
+ @Nullable ICompanionDeviceManager iPCInterface) {
this.mNum = num;
this.mNum2 = num2;
this.mNum4 = num4;
@@ -597,6 +616,10 @@ public final class SampleDataClass implements Parcelable {
"from", 0f);
}
+ this.mToken = token;
+ AnnotationValidations.validate(
+ NonNull.class, null, mToken);
+ this.mIPCInterface = iPCInterface;
onConstructed();
}
@@ -797,6 +820,22 @@ public final class SampleDataClass implements Parcelable {
}
/**
+ * Binder types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull IBinder getToken() {
+ return mToken;
+ }
+
+ /**
+ * AIDL interface types are also supported
+ */
+ @DataClass.Generated.Member
+ public @Nullable ICompanionDeviceManager getIPCInterface() {
+ return mIPCInterface;
+ }
+
+ /**
* When using transient fields for caching it's often also a good idea to initialize them
* lazily.
*
@@ -1089,6 +1128,26 @@ public final class SampleDataClass implements Parcelable {
return this;
}
+ /**
+ * Binder types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull SampleDataClass setToken(@NonNull IBinder value) {
+ mToken = value;
+ AnnotationValidations.validate(
+ NonNull.class, null, mToken);
+ return this;
+ }
+
+ /**
+ * AIDL interface types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull SampleDataClass setIPCInterface(@NonNull ICompanionDeviceManager value) {
+ mIPCInterface = value;
+ return this;
+ }
+
@Override
@DataClass.Generated.Member
public String toString() {
@@ -1115,7 +1174,9 @@ public final class SampleDataClass implements Parcelable {
"linkAddresses5 = " + java.util.Arrays.toString(mLinkAddresses5) + ", " +
"stringRes = " + mStringRes + ", " +
"dayOfWeek = " + mDayOfWeek + ", " +
- "coords = " + java.util.Arrays.toString(mCoords) +
+ "coords = " + java.util.Arrays.toString(mCoords) + ", " +
+ "token = " + mToken + ", " +
+ "iPCInterface = " + mIPCInterface +
" }";
}
@@ -1151,7 +1212,9 @@ public final class SampleDataClass implements Parcelable {
&& java.util.Arrays.equals(mLinkAddresses5, that.mLinkAddresses5)
&& mStringRes == that.mStringRes
&& mDayOfWeek == that.mDayOfWeek
- && java.util.Arrays.equals(mCoords, that.mCoords);
+ && java.util.Arrays.equals(mCoords, that.mCoords)
+ && Objects.equals(mToken, that.mToken)
+ && Objects.equals(mIPCInterface, that.mIPCInterface);
}
@Override
@@ -1181,6 +1244,8 @@ public final class SampleDataClass implements Parcelable {
_hash = 31 * _hash + mStringRes;
_hash = 31 * _hash + mDayOfWeek;
_hash = 31 * _hash + java.util.Arrays.hashCode(mCoords);
+ _hash = 31 * _hash + Objects.hashCode(mToken);
+ _hash = 31 * _hash + Objects.hashCode(mIPCInterface);
return _hash;
}
@@ -1208,6 +1273,8 @@ public final class SampleDataClass implements Parcelable {
actionInt.acceptInt(this, "stringRes", mStringRes);
actionInt.acceptInt(this, "dayOfWeek", mDayOfWeek);
actionObject.acceptObject(this, "coords", mCoords);
+ actionObject.acceptObject(this, "token", mToken);
+ actionObject.acceptObject(this, "iPCInterface", mIPCInterface);
}
/** @deprecated May cause boxing allocations - use with caution! */
@@ -1234,6 +1301,8 @@ public final class SampleDataClass implements Parcelable {
action.acceptObject(this, "stringRes", mStringRes);
action.acceptObject(this, "dayOfWeek", mDayOfWeek);
action.acceptObject(this, "coords", mCoords);
+ action.acceptObject(this, "token", mToken);
+ action.acceptObject(this, "iPCInterface", mIPCInterface);
}
@DataClass.Generated.Member
@@ -1269,6 +1338,7 @@ public final class SampleDataClass implements Parcelable {
if (mOtherParcelable != null) flg |= 0x40;
if (mLinkAddresses4 != null) flg |= 0x800;
if (mLinkAddresses5 != null) flg |= 0x10000;
+ if (mIPCInterface != null) flg |= 0x200000;
dest.writeLong(flg);
dest.writeInt(mNum);
dest.writeInt(mNum2);
@@ -1290,6 +1360,8 @@ public final class SampleDataClass implements Parcelable {
dest.writeInt(mStringRes);
dest.writeInt(mDayOfWeek);
dest.writeFloatArray(mCoords);
+ dest.writeStrongBinder(mToken);
+ if (mIPCInterface != null) dest.writeStrongInterface(mIPCInterface);
}
@Override
@@ -1326,6 +1398,8 @@ public final class SampleDataClass implements Parcelable {
int stringRes = in.readInt();
int dayOfWeek = in.readInt();
float[] coords = in.createFloatArray();
+ IBinder token = (IBinder) in.readStrongBinder();
+ ICompanionDeviceManager iPCInterface = (flg & 0x200000) == 0 ? null : ICompanionDeviceManager.Stub.asInterface(in.readStrongBinder());
this.mNum = num;
this.mNum2 = num2;
@@ -1409,6 +1483,10 @@ public final class SampleDataClass implements Parcelable {
"from", 0f);
}
+ this.mToken = token;
+ AnnotationValidations.validate(
+ NonNull.class, null, mToken);
+ this.mIPCInterface = iPCInterface;
onConstructed();
}
@@ -1454,6 +1532,8 @@ public final class SampleDataClass implements Parcelable {
private @StringRes int mStringRes;
private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek;
private @Size(2) @NonNull @FloatRange(from = 0f) float[] mCoords;
+ private @NonNull IBinder mToken;
+ private @Nullable ICompanionDeviceManager mIPCInterface;
private long mBuilderFieldsSet = 0L;
@@ -1794,10 +1874,32 @@ public final class SampleDataClass implements Parcelable {
return this;
}
+ /**
+ * Binder types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setToken(@NonNull IBinder value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x100000;
+ mToken = value;
+ return this;
+ }
+
+ /**
+ * AIDL interface types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setIPCInterface(@NonNull ICompanionDeviceManager value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x200000;
+ mIPCInterface = value;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull SampleDataClass build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x100000; // Mark builder used
+ mBuilderFieldsSet |= 0x400000; // Mark builder used
if ((mBuilderFieldsSet & 0x10) == 0) {
mName2 = "Bob";
@@ -1841,6 +1943,12 @@ public final class SampleDataClass implements Parcelable {
if ((mBuilderFieldsSet & 0x80000) == 0) {
mCoords = new float[] { 0f, 0f };
}
+ if ((mBuilderFieldsSet & 0x100000) == 0) {
+ mToken = new Binder();
+ }
+ if ((mBuilderFieldsSet & 0x200000) == 0) {
+ mIPCInterface = null;
+ }
SampleDataClass o = new SampleDataClass(
mNum,
mNum2,
@@ -1861,12 +1969,14 @@ public final class SampleDataClass implements Parcelable {
mLinkAddresses5,
mStringRes,
mDayOfWeek,
- mCoords);
+ mCoords,
+ mToken,
+ mIPCInterface);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x100000) != 0) {
+ if ((mBuilderFieldsSet & 0x400000) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -1874,10 +1984,10 @@ public final class SampleDataClass implements Parcelable {
}
@DataClass.Generated(
- time = 1604522372172L,
- codegenVersion = "1.0.20",
+ time = 1616541539978L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
- inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final int STATE_UNDEFINED\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange int mDayOfWeek\nprivate @android.annotation.Size @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
+ inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final int STATE_UNDEFINED\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange int mDayOfWeek\nprivate @android.annotation.Size @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange float[] mCoords\nprivate @android.annotation.NonNull android.os.IBinder mToken\nprivate @android.annotation.Nullable android.companion.ICompanionDeviceManager mIPCInterface\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
@Deprecated
private void __metadata() {}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index 3ab34452f9fc..a535e227cccf 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -85,7 +85,7 @@ public class SampleWithCustomBuilder implements Parcelable {
- // Code below generated by codegen v1.0.20.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -253,8 +253,8 @@ public class SampleWithCustomBuilder implements Parcelable {
}
@DataClass.Generated(
- time = 1604522373190L,
- codegenVersion = "1.0.20",
+ time = 1616541540898L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
index 8901cac1cb1b..d40962456741 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
@@ -36,7 +36,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.20.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -135,8 +135,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1604522377998L,
- codegenVersion = "1.0.20",
+ time = 1616541545539L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBar\nclass NestedDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -160,7 +160,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.20.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -259,8 +259,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1604522378007L,
- codegenVersion = "1.0.20",
+ time = 1616541545548L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull long mBaz2\nclass NestedDataClass3 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -274,7 +274,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.20.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -373,8 +373,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1604522378015L,
- codegenVersion = "1.0.20",
+ time = 1616541545552L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBaz\nclass NestedDataClass2 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
index ac776f3c2764..3583b95fb4ce 100644
--- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
+++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
@@ -64,7 +64,7 @@ public class StaleDataclassDetectorFalsePositivesTest {
- // Code below generated by codegen v1.0.20.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -89,8 +89,8 @@ public class StaleDataclassDetectorFalsePositivesTest {
}
@DataClass.Generated(
- time = 1604522377011L,
- codegenVersion = "1.0.20",
+ time = 1616541544639L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java",
inputSignatures = "private @android.annotation.Nullable java.util.List<java.util.Set<?>> mUsesWildcards\npublic @android.annotation.NonNull java.lang.String someMethod(int)\nprivate @android.annotation.IntRange void annotatedWithConstArg()\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
@Deprecated
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index fd376528aa44..44298d4b7652 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -265,6 +265,7 @@ import android.security.Credentials;
import android.system.Os;
import android.telephony.TelephonyManager;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.test.mock.MockContentResolver;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -9963,7 +9964,7 @@ public class ConnectivityServiceTest {
&& session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionLost(qosCallbackId, sessionId);
+ .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_EPS_BEARER);
waitForIdle();
verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
session.getSessionId() == sessionId
@@ -9971,6 +9972,36 @@ public class ConnectivityServiceTest {
}
@Test
+ public void testNrQosCallbackAvailableAndLost() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final int sessionId = 10;
+ final int qosCallbackId = 1;
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ waitForIdle();
+
+ final NrQosSessionAttributes attributes = new NrQosSessionAttributes(
+ 1, 2, 3, 4, 5, 6, 7, new ArrayList<>());
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
+ waitForIdle();
+
+ verify(mQosCallbackMockHelper.mCallback).onNrQosSessionAvailable(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_NR_BEARER), eq(attributes));
+
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_NR_BEARER);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_NR_BEARER));
+ }
+
+ @Test
public void testQosCallbackTooManyRequests() throws Exception {
mQosCallbackMockHelper = new QosCallbackMockHelper();
diff --git a/tools/codegen/src/com/android/codegen/FieldInfo.kt b/tools/codegen/src/com/android/codegen/FieldInfo.kt
index 02ebaef90f0b..74392ddc30e6 100644
--- a/tools/codegen/src/com/android/codegen/FieldInfo.kt
+++ b/tools/codegen/src/com/android/codegen/FieldInfo.kt
@@ -220,11 +220,12 @@ data class FieldInfo(
isBinder(FieldInnerType!!) -> "BinderList"
else -> "ParcelableList"
}
+ isStrongBinder(Type) -> "StrongBinder"
isIInterface(Type) -> "StrongInterface"
- isBinder(Type) -> "StrongBinder"
else -> "TypedObject"
}.capitalize()
+ private fun isStrongBinder(type: String) = type == "Binder" || type == "IBinder"
private fun isBinder(type: String) = type == "Binder" || type == "IBinder" || isIInterface(type)
private fun isIInterface(type: String) = type.length >= 2 && type[0] == 'I' && type[1].isUpperCase()
} \ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index d9ad649782bb..4da401951470 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
package com.android.codegen
const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.22"
+const val CODEGEN_VERSION = "1.0.23"
const val CANONICAL_BUILDER_CLASS = "Builder"
const val BASE_BUILDER_CLASS = "BaseBuilder"